diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-08-10 18:13:17 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-08-10 18:13:17 -0400 |
| commit | e84ba17b9f48a3bc8811b1a89c54c25bc6607599 (patch) | |
| tree | 220ce22658497f75f4d575296fc903cd19a60339 /MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs | |
| parent | 0f508dab47ebcc27d973840d03025f28f52a14b6 (diff) | |
add activity log feature
Diffstat (limited to 'MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs new file mode 100644 index 000000000..787cbcc5b --- /dev/null +++ b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs @@ -0,0 +1,293 @@ +using MediaBrowser.Controller; +using MediaBrowser.Controller.Activity; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; +using MediaBrowser.Server.Implementations.Persistence; +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Activity +{ + public class ActivityRepository : IActivityRepository, IDisposable + { + private IDbConnection _connection; + private readonly ILogger _logger; + private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1); + private readonly IServerApplicationPaths _appPaths; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + private IDbCommand _saveActivityCommand; + + public ActivityRepository(ILogger logger, IServerApplicationPaths appPaths) + { + _logger = logger; + _appPaths = appPaths; + } + + public async Task Initialize() + { + var dbFile = Path.Combine(_appPaths.DataPath, "activitylog.db"); + + _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false); + + string[] queries = { + + "create table if not exists ActivityLogEntries (Id GUID PRIMARY KEY, Name TEXT, Overview TEXT, ShortOverview TEXT, Type TEXT, ItemId TEXT, UserId TEXT, DateCreated DATETIME, LogSeverity TEXT)", + "create index if not exists idx_ActivityLogEntries on ActivityLogEntries(Id)", + + //pragmas + "pragma temp_store = memory", + + "pragma shrink_memory" + }; + + _connection.RunQueries(queries, _logger); + + PrepareStatements(); + } + + private void PrepareStatements() + { + _saveActivityCommand = _connection.CreateCommand(); + _saveActivityCommand.CommandText = "replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)"; + + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Id"); + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Name"); + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Overview"); + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@ShortOverview"); + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@Type"); + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@ItemId"); + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@UserId"); + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@DateCreated"); + _saveActivityCommand.Parameters.Add(_saveActivityCommand, "@LogSeverity"); + } + + private const string BaseActivitySelectText = "select Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity from ActivityLogEntries"; + + public Task Create(ActivityLogEntry entry) + { + return Update(entry); + } + + public async Task Update(ActivityLogEntry entry) + { + if (entry == null) + { + throw new ArgumentNullException("entry"); + } + + await _writeLock.WaitAsync().ConfigureAwait(false); + + IDbTransaction transaction = null; + + try + { + transaction = _connection.BeginTransaction(); + + var index = 0; + + _saveActivityCommand.GetParameter(index++).Value = new Guid(entry.Id); + _saveActivityCommand.GetParameter(index++).Value = entry.Name; + _saveActivityCommand.GetParameter(index++).Value = entry.Overview; + _saveActivityCommand.GetParameter(index++).Value = entry.ShortOverview; + _saveActivityCommand.GetParameter(index++).Value = entry.Type; + _saveActivityCommand.GetParameter(index++).Value = entry.ItemId; + _saveActivityCommand.GetParameter(index++).Value = entry.UserId; + _saveActivityCommand.GetParameter(index++).Value = entry.Date; + _saveActivityCommand.GetParameter(index++).Value = entry.Severity.ToString(); + + _saveActivityCommand.Transaction = transaction; + + _saveActivityCommand.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + _logger.ErrorException("Failed to save record:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + + _writeLock.Release(); + } + } + + public QueryResult<ActivityLogEntry> GetActivityLogEntries(int? startIndex, int? limit) + { + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = BaseActivitySelectText; + + var whereClauses = new List<string>(); + + if (startIndex.HasValue && startIndex.Value > 0) + { + whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLogEntries ORDER BY DateCreated DESC LIMIT {0})", + startIndex.Value.ToString(_usCulture))); + } + + if (whereClauses.Count > 0) + { + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); + } + + cmd.CommandText += " ORDER BY DateCreated DESC"; + + if (limit.HasValue) + { + cmd.CommandText += " LIMIT " + limit.Value.ToString(_usCulture); + } + + cmd.CommandText += "; select count (Id) from ActivityLogEntries"; + + var list = new List<ActivityLogEntry>(); + var count = 0; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + while (reader.Read()) + { + list.Add(GetEntry(reader)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult<ActivityLogEntry>() + { + Items = list.ToArray(), + TotalRecordCount = count + }; + } + } + + private ActivityLogEntry GetEntry(IDataReader reader) + { + var index = 0; + + var info = new ActivityLogEntry + { + Id = reader.GetGuid(index).ToString("N") + }; + + index++; + if (!reader.IsDBNull(index)) + { + info.Name = reader.GetString(index); + } + + index++; + if (!reader.IsDBNull(index)) + { + info.Overview = reader.GetString(index); + } + + index++; + if (!reader.IsDBNull(index)) + { + info.ShortOverview = reader.GetString(index); + } + + index++; + if (!reader.IsDBNull(index)) + { + info.Type = reader.GetString(index); + } + + index++; + if (!reader.IsDBNull(index)) + { + info.ItemId = reader.GetString(index); + } + + index++; + if (!reader.IsDBNull(index)) + { + info.UserId = reader.GetString(index); + } + + index++; + info.Date = reader.GetDateTime(index).ToUniversalTime(); + + index++; + if (!reader.IsDBNull(index)) + { + info.Severity = (LogSeverity)Enum.Parse(typeof(LogSeverity), reader.GetString(index), true); + } + + return info; + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private readonly object _disposeLock = new object(); + + /// <summary> + /// Releases unmanaged and - optionally - managed resources. + /// </summary> + /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + try + { + lock (_disposeLock) + { + if (_connection != null) + { + if (_connection.IsOpen()) + { + _connection.Close(); + } + + _connection.Dispose(); + _connection = null; + } + } + } + catch (Exception ex) + { + _logger.ErrorException("Error disposing database", ex); + } + } + } + } +} |
