diff options
Diffstat (limited to 'Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs')
| -rw-r--r-- | Emby.Server.Implementations/Devices/SqliteDeviceRepository.cs | 441 |
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) + { + } + } + } + } +} |
