aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs')
-rw-r--r--Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs441
1 files changed, 441 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs b/Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs
new file mode 100644
index 000000000..e8b7466a5
--- /dev/null
+++ b/Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs
@@ -0,0 +1,441 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using Emby.Server.Implementations.Data;
+using MediaBrowser.Controller;
+using MediaBrowser.Model.Logging;
+using SQLitePCL.pretty;
+using MediaBrowser.Model.Extensions;
+using MediaBrowser.Model.IO;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Model.Devices;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Session;
+using MediaBrowser.Controller.Configuration;
+
+namespace Emby.Server.Implementations.Devices
+{
+ public class SqliteDeviceRepository : BaseSqliteRepository, IDeviceRepository
+ {
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+ protected IFileSystem FileSystem { get; private set; }
+ private readonly object _syncLock = new object();
+ private readonly IJsonSerializer _json;
+ private IServerApplicationPaths _appPaths;
+
+ public SqliteDeviceRepository(ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem, IJsonSerializer json)
+ : base(logger)
+ {
+ var appPaths = config.ApplicationPaths;
+
+ DbFilePath = Path.Combine(appPaths.DataPath, "devices.db");
+ FileSystem = fileSystem;
+ _json = json;
+ _appPaths = appPaths;
+ }
+
+ public void Initialize()
+ {
+ try
+ {
+ InitializeInternal();
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading database file. Will reset and retry.", ex);
+
+ FileSystem.DeleteFile(DbFilePath);
+
+ InitializeInternal();
+ }
+ }
+
+ private void InitializeInternal()
+ {
+ using (var connection = CreateConnection())
+ {
+ RunDefaultInitialization(connection);
+
+ string[] queries = {
+ "create table if not exists Devices (Id TEXT PRIMARY KEY, Name TEXT, ReportedName TEXT, CustomName TEXT, CameraUploadPath TEXT, LastUserName TEXT, AppName TEXT, AppVersion TEXT, LastUserId TEXT, DateLastModified DATETIME, Capabilities TEXT)",
+ "create index if not exists idx_id on Devices(Id)"
+ };
+
+ connection.RunQueries(queries);
+
+ MigrateDevices();
+ }
+ }
+
+ private void MigrateDevices()
+ {
+ var files = FileSystem
+ .GetFilePaths(GetDevicesPath(), true)
+ .Where(i => string.Equals(Path.GetFileName(i), "device.json", StringComparison.OrdinalIgnoreCase))
+ .ToList();
+
+ foreach (var file in files)
+ {
+ try
+ {
+ var device = _json.DeserializeFromFile<DeviceInfo>(file);
+
+ SaveDevice(device);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error reading {0}", ex, file);
+ }
+ finally
+ {
+ try
+ {
+ FileSystem.DeleteFile(file);
+ }
+ catch (IOException)
+ {
+ try
+ {
+ FileSystem.MoveFile(file, Path.ChangeExtension(file, ".old"));
+ }
+ catch (IOException)
+ {
+ }
+ }
+ }
+ }
+ }
+
+ private const string BaseSelectText = "select Id, Name, ReportedName, CustomName, CameraUploadPath, LastUserName, AppName, AppVersion, LastUserId, DateLastModified, Capabilities from Devices";
+
+ public void SaveCapabilities(string deviceId, ClientCapabilities capabilities)
+ {
+ using (WriteLock.Write())
+ {
+ using (var connection = CreateConnection())
+ {
+ connection.RunInTransaction(db =>
+ {
+ using (var statement = db.PrepareStatement("update devices set Capabilities=@Capabilities where Id=@Id"))
+ {
+ statement.TryBind("@Id", deviceId);
+
+ if (capabilities == null)
+ {
+ statement.TryBindNull("@Capabilities");
+ }
+ else
+ {
+ statement.TryBind("@Capabilities", _json.SerializeToString(capabilities));
+ }
+
+ statement.MoveNext();
+ }
+ }, TransactionMode);
+ }
+ }
+ }
+
+ public void SaveDevice(DeviceInfo entry)
+ {
+ if (entry == null)
+ {
+ throw new ArgumentNullException("entry");
+ }
+
+ using (WriteLock.Write())
+ {
+ using (var connection = CreateConnection())
+ {
+ connection.RunInTransaction(db =>
+ {
+ using (var statement = db.PrepareStatement("replace into Devices (Id, Name, ReportedName, CustomName, CameraUploadPath, LastUserName, AppName, AppVersion, LastUserId, DateLastModified, Capabilities) values (@Id, @Name, @ReportedName, @CustomName, @CameraUploadPath, @LastUserName, @AppName, @AppVersion, @LastUserId, @DateLastModified, @Capabilities)"))
+ {
+ statement.TryBind("@Id", entry.Id);
+ statement.TryBind("@Name", entry.Name);
+ statement.TryBind("@ReportedName", entry.ReportedName);
+ statement.TryBind("@CustomName", entry.CustomName);
+ statement.TryBind("@CameraUploadPath", entry.CameraUploadPath);
+ statement.TryBind("@LastUserName", entry.LastUserName);
+ statement.TryBind("@AppName", entry.AppName);
+ statement.TryBind("@AppVersion", entry.AppVersion);
+ statement.TryBind("@DateLastModified", entry.DateLastModified);
+
+ if (entry.Capabilities == null)
+ {
+ statement.TryBindNull("@Capabilities");
+ }
+ else
+ {
+ statement.TryBind("@Capabilities", _json.SerializeToString(entry.Capabilities));
+ }
+
+ statement.MoveNext();
+ }
+ }, TransactionMode);
+ }
+ }
+ }
+
+ public DeviceInfo GetDevice(string id)
+ {
+ using (WriteLock.Read())
+ {
+ using (var connection = CreateConnection(true))
+ {
+ var statementTexts = new List<string>();
+ statementTexts.Add(BaseSelectText + " where Id=@Id");
+
+ return connection.RunInTransaction(db =>
+ {
+ var statements = PrepareAllSafe(db, statementTexts).ToList();
+
+ using (var statement = statements[0])
+ {
+ statement.TryBind("@Id", id);
+
+ foreach (var row in statement.ExecuteQuery())
+ {
+ return GetEntry(row);
+ }
+ }
+
+ return null;
+
+ }, ReadTransactionMode);
+ }
+ }
+ }
+
+ public List<DeviceInfo> GetDevices()
+ {
+ using (WriteLock.Read())
+ {
+ using (var connection = CreateConnection(true))
+ {
+ var statementTexts = new List<string>();
+ statementTexts.Add(BaseSelectText + " order by DateLastModified desc");
+
+ return connection.RunInTransaction(db =>
+ {
+ var list = new List<DeviceInfo>();
+
+ var statements = PrepareAllSafe(db, statementTexts).ToList();
+
+ using (var statement = statements[0])
+ {
+ foreach (var row in statement.ExecuteQuery())
+ {
+ list.Add(GetEntry(row));
+ }
+ }
+
+ return list;
+
+ }, ReadTransactionMode);
+ }
+ }
+ }
+
+ public ClientCapabilities GetCapabilities(string id)
+ {
+ using (WriteLock.Read())
+ {
+ using (var connection = CreateConnection(true))
+ {
+ var statementTexts = new List<string>();
+ statementTexts.Add("Select Capabilities from Devices where Id=@Id");
+
+ return connection.RunInTransaction(db =>
+ {
+ var statements = PrepareAllSafe(db, statementTexts).ToList();
+
+ using (var statement = statements[0])
+ {
+ statement.TryBind("@Id", id);
+
+ foreach (var row in statement.ExecuteQuery())
+ {
+ if (row[0].SQLiteType != SQLiteType.Null)
+ {
+ return _json.DeserializeFromString<ClientCapabilities>(row.GetString(0));
+ }
+ }
+ }
+
+ return null;
+
+ }, ReadTransactionMode);
+ }
+ }
+ }
+
+ private DeviceInfo GetEntry(IReadOnlyList<IResultSetValue> reader)
+ {
+ var index = 0;
+
+ var info = new DeviceInfo
+ {
+ Id = reader.GetString(index)
+ };
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.Name = reader.GetString(index);
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.ReportedName = reader.GetString(index);
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.CustomName = reader.GetString(index);
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.CameraUploadPath = reader.GetString(index);
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.LastUserName = reader.GetString(index);
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.AppName = reader.GetString(index);
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.AppVersion = reader.GetString(index);
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.LastUserId = reader.GetString(index);
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.DateLastModified = reader[index].ReadDateTime();
+ }
+
+ index++;
+ if (reader[index].SQLiteType != SQLiteType.Null)
+ {
+ info.Capabilities = _json.DeserializeFromString<ClientCapabilities>(reader.GetString(index));
+ }
+
+ return info;
+ }
+
+ private string GetDevicesPath()
+ {
+ return Path.Combine(_appPaths.DataPath, "devices");
+ }
+
+ private string GetDevicePath(string id)
+ {
+ return Path.Combine(GetDevicesPath(), id.GetMD5().ToString("N"));
+ }
+
+ public ContentUploadHistory GetCameraUploadHistory(string deviceId)
+ {
+ var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
+
+ lock (_syncLock)
+ {
+ try
+ {
+ return _json.DeserializeFromFile<ContentUploadHistory>(path);
+ }
+ catch (IOException)
+ {
+ return new ContentUploadHistory
+ {
+ DeviceId = deviceId
+ };
+ }
+ }
+ }
+
+ public void AddCameraUpload(string deviceId, LocalFileInfo file)
+ {
+ var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json");
+ FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path));
+
+ lock (_syncLock)
+ {
+ ContentUploadHistory history;
+
+ try
+ {
+ history = _json.DeserializeFromFile<ContentUploadHistory>(path);
+ }
+ catch (IOException)
+ {
+ history = new ContentUploadHistory
+ {
+ DeviceId = deviceId
+ };
+ }
+
+ history.DeviceId = deviceId;
+
+ var list = history.FilesUploaded.ToList();
+ list.Add(file);
+ history.FilesUploaded = list.ToArray(list.Count);
+
+ _json.SerializeToFile(history, path);
+ }
+ }
+
+ public void DeleteDevice(string id)
+ {
+ using (WriteLock.Write())
+ {
+ using (var connection = CreateConnection())
+ {
+ connection.RunInTransaction(db =>
+ {
+ using (var statement = db.PrepareStatement("delete from devices where Id=@Id"))
+ {
+ statement.TryBind("@Id", id);
+
+ statement.MoveNext();
+ }
+ }, TransactionMode);
+ }
+ }
+
+ var path = GetDevicePath(id);
+
+ lock (_syncLock)
+ {
+ try
+ {
+ FileSystem.DeleteDirectory(path, true);
+ }
+ catch (IOException)
+ {
+ }
+ }
+ }
+ }
+}