aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Sync/TargetDataProvider.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Sync/TargetDataProvider.cs')
-rw-r--r--Emby.Server.Implementations/Sync/TargetDataProvider.cs188
1 files changed, 188 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/Sync/TargetDataProvider.cs b/Emby.Server.Implementations/Sync/TargetDataProvider.cs
new file mode 100644
index 000000000..a0e0f4313
--- /dev/null
+++ b/Emby.Server.Implementations/Sync/TargetDataProvider.cs
@@ -0,0 +1,188 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Sync;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Sync;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.IO;
+
+namespace Emby.Server.Implementations.Sync
+{
+ public class TargetDataProvider : ISyncDataProvider
+ {
+ private readonly SyncTarget _target;
+ private readonly IServerSyncProvider _provider;
+
+ private readonly SemaphoreSlim _dataLock = new SemaphoreSlim(1, 1);
+ private List<LocalItem> _items;
+
+ private readonly ILogger _logger;
+ private readonly IJsonSerializer _json;
+ private readonly IFileSystem _fileSystem;
+ private readonly IApplicationPaths _appPaths;
+ private readonly IServerApplicationHost _appHost;
+ private readonly IMemoryStreamProvider _memoryStreamProvider;
+
+ public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, IServerApplicationHost appHost, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths, IMemoryStreamProvider memoryStreamProvider)
+ {
+ _logger = logger;
+ _json = json;
+ _provider = provider;
+ _target = target;
+ _fileSystem = fileSystem;
+ _appPaths = appPaths;
+ _memoryStreamProvider = memoryStreamProvider;
+ _appHost = appHost;
+ }
+
+ private string[] GetRemotePath()
+ {
+ var parts = new List<string>
+ {
+ _appHost.FriendlyName,
+ "data.json"
+ };
+
+ parts = parts.Select(i => GetValidFilename(_provider, i)).ToList();
+
+ return parts.ToArray();
+ }
+
+ private string GetValidFilename(IServerSyncProvider provider, string filename)
+ {
+ // We can always add this method to the sync provider if it's really needed
+ return _fileSystem.GetValidFilename(filename);
+ }
+
+ private async Task<List<LocalItem>> RetrieveItems(CancellationToken cancellationToken)
+ {
+ _logger.Debug("Getting {0} from {1}", string.Join(MediaSync.PathSeparatorString, GetRemotePath().ToArray()), _provider.Name);
+
+ var fileResult = await _provider.GetFiles(GetRemotePath().ToArray(), _target, cancellationToken).ConfigureAwait(false);
+
+ if (fileResult.Items.Length > 0)
+ {
+ using (var stream = await _provider.GetFile(fileResult.Items[0].FullName, _target, new Progress<double>(), cancellationToken))
+ {
+ return _json.DeserializeFromStream<List<LocalItem>>(stream);
+ }
+ }
+
+ return new List<LocalItem>();
+ }
+
+ private async Task EnsureData(CancellationToken cancellationToken)
+ {
+ if (_items == null)
+ {
+ _items = await RetrieveItems(cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private async Task SaveData(List<LocalItem> items, CancellationToken cancellationToken)
+ {
+ using (var stream = _memoryStreamProvider.CreateNew())
+ {
+ _json.SerializeToStream(items, stream);
+
+ // Save to sync provider
+ stream.Position = 0;
+ var remotePath = GetRemotePath();
+ _logger.Debug("Saving data.json to {0}. Remote path: {1}", _provider.Name, string.Join("/", remotePath));
+
+ await _provider.SendFile(stream, remotePath, _target, new Progress<double>(), cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ private async Task<T> GetData<T>(bool enableCache, Func<List<LocalItem>, T> dataFactory)
+ {
+ if (!enableCache)
+ {
+ var items = await RetrieveItems(CancellationToken.None).ConfigureAwait(false);
+ var newCache = items.ToList();
+ var result = dataFactory(items);
+ await UpdateCache(newCache).ConfigureAwait(false);
+ return result;
+ }
+
+ await _dataLock.WaitAsync().ConfigureAwait(false);
+
+ try
+ {
+ await EnsureData(CancellationToken.None).ConfigureAwait(false);
+
+ return dataFactory(_items);
+ }
+ finally
+ {
+ _dataLock.Release();
+ }
+ }
+
+ private async Task UpdateData(Func<List<LocalItem>, List<LocalItem>> action)
+ {
+ var items = await RetrieveItems(CancellationToken.None).ConfigureAwait(false);
+ items = action(items);
+ await SaveData(items.ToList(), CancellationToken.None).ConfigureAwait(false);
+
+ await UpdateCache(null).ConfigureAwait(false);
+ }
+
+ private async Task UpdateCache(List<LocalItem> list)
+ {
+ await _dataLock.WaitAsync().ConfigureAwait(false);
+
+ try
+ {
+ _items = list;
+ }
+ finally
+ {
+ _dataLock.Release();
+ }
+ }
+
+ public Task<List<LocalItem>> GetLocalItems(SyncTarget target, string serverId)
+ {
+ return GetData(false, items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).ToList());
+ }
+
+ public Task AddOrUpdate(SyncTarget target, LocalItem item)
+ {
+ return UpdateData(items =>
+ {
+ var list = items.Where(i => !string.Equals(i.Id, item.Id, StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ list.Add(item);
+
+ return list;
+ });
+ }
+
+ public Task Delete(SyncTarget target, string id)
+ {
+ return UpdateData(items => items.Where(i => !string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase)).ToList());
+ }
+
+ public Task<LocalItem> Get(SyncTarget target, string id)
+ {
+ return GetData(true, items => items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase)));
+ }
+
+ public Task<List<LocalItem>> GetItems(SyncTarget target, string serverId, string itemId)
+ {
+ return GetData(true, items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.ItemId, itemId, StringComparison.OrdinalIgnoreCase)).ToList());
+ }
+
+ public Task<List<LocalItem>> GetItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId)
+ {
+ return GetData(false, items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.SyncJobItemId, syncJobItemId, StringComparison.OrdinalIgnoreCase)).ToList());
+ }
+ }
+}