Merge pull request #452 from Bond-009/activitydb

Use EF Core for Activity database
This commit is contained in:
Andrew Rabert 2019-01-24 23:02:20 -05:00 committed by GitHub
commit 48ad18d12b
10 changed files with 109 additions and 369 deletions

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates; using MediaBrowser.Common.Updates;
@ -92,18 +93,18 @@ namespace Emby.Server.Implementations.Activity
_appHost.ApplicationUpdated += _appHost_ApplicationUpdated; _appHost.ApplicationUpdated += _appHost_ApplicationUpdated;
} }
void _deviceManager_CameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e) async void _deviceManager_CameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("CameraImageUploadedFrom"), e.Argument.Device.Name), Name = string.Format(_localization.GetLocalizedString("CameraImageUploadedFrom"), e.Argument.Device.Name),
Type = NotificationType.CameraImageUploaded.ToString() Type = NotificationType.CameraImageUploaded.ToString()
}); });
} }
void _userManager_UserLockedOut(object sender, GenericEventArgs<User> e) async void _userManager_UserLockedOut(object sender, GenericEventArgs<User> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserLockedOutWithName"), e.Argument.Name), Name = string.Format(_localization.GetLocalizedString("UserLockedOutWithName"), e.Argument.Name),
Type = NotificationType.UserLockedOut.ToString(), Type = NotificationType.UserLockedOut.ToString(),
@ -111,9 +112,9 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _subManager_SubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e) async void _subManager_SubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"), e.Provider, Notifications.Notifications.GetItemName(e.Item)), Name = string.Format(_localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"), e.Provider, Notifications.Notifications.GetItemName(e.Item)),
Type = "SubtitleDownloadFailure", Type = "SubtitleDownloadFailure",
@ -122,7 +123,7 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _sessionManager_PlaybackStopped(object sender, PlaybackStopEventArgs e) async void _sessionManager_PlaybackStopped(object sender, PlaybackStopEventArgs e)
{ {
var item = e.MediaInfo; var item = e.MediaInfo;
@ -145,7 +146,7 @@ namespace Emby.Server.Implementations.Activity
var user = e.Users.First(); var user = e.Users.First();
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserStoppedPlayingItemWithValues"), user.Name, GetItemName(item), e.DeviceName), Name = string.Format(_localization.GetLocalizedString("UserStoppedPlayingItemWithValues"), user.Name, GetItemName(item), e.DeviceName),
Type = GetPlaybackStoppedNotificationType(item.MediaType), Type = GetPlaybackStoppedNotificationType(item.MediaType),
@ -153,7 +154,7 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e) async void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e)
{ {
var item = e.MediaInfo; var item = e.MediaInfo;
@ -176,7 +177,7 @@ namespace Emby.Server.Implementations.Activity
var user = e.Users.First(); var user = e.Users.First();
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserStartedPlayingItemWithValues"), user.Name, GetItemName(item), e.DeviceName), Name = string.Format(_localization.GetLocalizedString("UserStartedPlayingItemWithValues"), user.Name, GetItemName(item), e.DeviceName),
Type = GetPlaybackNotificationType(item.MediaType), Type = GetPlaybackNotificationType(item.MediaType),
@ -237,7 +238,7 @@ namespace Emby.Server.Implementations.Activity
return null; return null;
} }
void _sessionManager_SessionEnded(object sender, SessionEventArgs e) async void _sessionManager_SessionEnded(object sender, SessionEventArgs e)
{ {
string name; string name;
var session = e.SessionInfo; var session = e.SessionInfo;
@ -254,7 +255,7 @@ namespace Emby.Server.Implementations.Activity
name = string.Format(_localization.GetLocalizedString("UserOfflineFromDevice"), session.UserName, session.DeviceName); name = string.Format(_localization.GetLocalizedString("UserOfflineFromDevice"), session.UserName, session.DeviceName);
} }
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = name, Name = name,
Type = "SessionEnded", Type = "SessionEnded",
@ -263,11 +264,11 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _sessionManager_AuthenticationSucceeded(object sender, GenericEventArgs<AuthenticationResult> e) async void _sessionManager_AuthenticationSucceeded(object sender, GenericEventArgs<AuthenticationResult> e)
{ {
var user = e.Argument.User; var user = e.Argument.User;
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("AuthenticationSucceededWithUserName"), user.Name), Name = string.Format(_localization.GetLocalizedString("AuthenticationSucceededWithUserName"), user.Name),
Type = "AuthenticationSucceeded", Type = "AuthenticationSucceeded",
@ -276,9 +277,9 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _sessionManager_AuthenticationFailed(object sender, GenericEventArgs<AuthenticationRequest> e) async void _sessionManager_AuthenticationFailed(object sender, GenericEventArgs<AuthenticationRequest> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("FailedLoginAttemptWithUserName"), e.Argument.Username), Name = string.Format(_localization.GetLocalizedString("FailedLoginAttemptWithUserName"), e.Argument.Username),
Type = "AuthenticationFailed", Type = "AuthenticationFailed",
@ -287,9 +288,9 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _appHost_ApplicationUpdated(object sender, GenericEventArgs<PackageVersionInfo> e) async void _appHost_ApplicationUpdated(object sender, GenericEventArgs<PackageVersionInfo> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("MessageApplicationUpdatedTo"), e.Argument.versionStr), Name = string.Format(_localization.GetLocalizedString("MessageApplicationUpdatedTo"), e.Argument.versionStr),
Type = NotificationType.ApplicationUpdateInstalled.ToString(), Type = NotificationType.ApplicationUpdateInstalled.ToString(),
@ -297,27 +298,27 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) async void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("MessageNamedServerConfigurationUpdatedWithValue"), e.Key), Name = string.Format(_localization.GetLocalizedString("MessageNamedServerConfigurationUpdatedWithValue"), e.Key),
Type = "NamedConfigurationUpdated" Type = "NamedConfigurationUpdated"
}); });
} }
void _config_ConfigurationUpdated(object sender, EventArgs e) async void _config_ConfigurationUpdated(object sender, EventArgs e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = _localization.GetLocalizedString("MessageServerConfigurationUpdated"), Name = _localization.GetLocalizedString("MessageServerConfigurationUpdated"),
Type = "ServerConfigurationUpdated" Type = "ServerConfigurationUpdated"
}); });
} }
void _userManager_UserPolicyUpdated(object sender, GenericEventArgs<User> e) async void _userManager_UserPolicyUpdated(object sender, GenericEventArgs<User> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserPolicyUpdatedWithName"), e.Argument.Name), Name = string.Format(_localization.GetLocalizedString("UserPolicyUpdatedWithName"), e.Argument.Name),
Type = "UserPolicyUpdated", Type = "UserPolicyUpdated",
@ -325,18 +326,18 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _userManager_UserDeleted(object sender, GenericEventArgs<User> e) async void _userManager_UserDeleted(object sender, GenericEventArgs<User> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserDeletedWithName"), e.Argument.Name), Name = string.Format(_localization.GetLocalizedString("UserDeletedWithName"), e.Argument.Name),
Type = "UserDeleted" Type = "UserDeleted"
}); });
} }
void _userManager_UserPasswordChanged(object sender, GenericEventArgs<User> e) async void _userManager_UserPasswordChanged(object sender, GenericEventArgs<User> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserPasswordChangedWithName"), e.Argument.Name), Name = string.Format(_localization.GetLocalizedString("UserPasswordChangedWithName"), e.Argument.Name),
Type = "UserPasswordChanged", Type = "UserPasswordChanged",
@ -344,9 +345,9 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _userManager_UserCreated(object sender, GenericEventArgs<User> e) async void _userManager_UserCreated(object sender, GenericEventArgs<User> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserCreatedWithName"), e.Argument.Name), Name = string.Format(_localization.GetLocalizedString("UserCreatedWithName"), e.Argument.Name),
Type = "UserCreated", Type = "UserCreated",
@ -354,9 +355,9 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _subManager_SubtitlesDownloaded(object sender, SubtitleDownloadEventArgs e) async void _subManager_SubtitlesDownloaded(object sender, SubtitleDownloadEventArgs e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("SubtitlesDownloadedForItem"), Notifications.Notifications.GetItemName(e.Item)), Name = string.Format(_localization.GetLocalizedString("SubtitlesDownloadedForItem"), Notifications.Notifications.GetItemName(e.Item)),
Type = "SubtitlesDownloaded", Type = "SubtitlesDownloaded",
@ -365,7 +366,7 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _sessionManager_SessionStarted(object sender, SessionEventArgs e) async void _sessionManager_SessionStarted(object sender, SessionEventArgs e)
{ {
string name; string name;
var session = e.SessionInfo; var session = e.SessionInfo;
@ -382,7 +383,7 @@ namespace Emby.Server.Implementations.Activity
name = string.Format(_localization.GetLocalizedString("UserOnlineFromDevice"), session.UserName, session.DeviceName); name = string.Format(_localization.GetLocalizedString("UserOnlineFromDevice"), session.UserName, session.DeviceName);
} }
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = name, Name = name,
Type = "SessionStarted", Type = "SessionStarted",
@ -391,9 +392,9 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _installationManager_PluginUpdated(object sender, GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>> e) async void _installationManager_PluginUpdated(object sender, GenericEventArgs<Tuple<IPlugin, PackageVersionInfo>> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("PluginUpdatedWithName"), e.Argument.Item1.Name), Name = string.Format(_localization.GetLocalizedString("PluginUpdatedWithName"), e.Argument.Item1.Name),
Type = NotificationType.PluginUpdateInstalled.ToString(), Type = NotificationType.PluginUpdateInstalled.ToString(),
@ -402,18 +403,18 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _installationManager_PluginUninstalled(object sender, GenericEventArgs<IPlugin> e) async void _installationManager_PluginUninstalled(object sender, GenericEventArgs<IPlugin> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("PluginUninstalledWithName"), e.Argument.Name), Name = string.Format(_localization.GetLocalizedString("PluginUninstalledWithName"), e.Argument.Name),
Type = NotificationType.PluginUninstalled.ToString() Type = NotificationType.PluginUninstalled.ToString()
}); });
} }
void _installationManager_PluginInstalled(object sender, GenericEventArgs<PackageVersionInfo> e) async void _installationManager_PluginInstalled(object sender, GenericEventArgs<PackageVersionInfo> e)
{ {
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("PluginInstalledWithName"), e.Argument.name), Name = string.Format(_localization.GetLocalizedString("PluginInstalledWithName"), e.Argument.name),
Type = NotificationType.PluginInstalled.ToString(), Type = NotificationType.PluginInstalled.ToString(),
@ -421,11 +422,11 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _installationManager_PackageInstallationFailed(object sender, InstallationFailedEventArgs e) async void _installationManager_PackageInstallationFailed(object sender, InstallationFailedEventArgs e)
{ {
var installationInfo = e.InstallationInfo; var installationInfo = e.InstallationInfo;
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("NameInstallFailed"), installationInfo.Name), Name = string.Format(_localization.GetLocalizedString("NameInstallFailed"), installationInfo.Name),
Type = NotificationType.InstallationFailed.ToString(), Type = NotificationType.InstallationFailed.ToString(),
@ -434,7 +435,7 @@ namespace Emby.Server.Implementations.Activity
}); });
} }
void _taskManager_TaskCompleted(object sender, TaskCompletionEventArgs e) async void _taskManager_TaskCompleted(object sender, TaskCompletionEventArgs e)
{ {
var result = e.Result; var result = e.Result;
var task = e.Task; var task = e.Task;
@ -461,7 +462,7 @@ namespace Emby.Server.Implementations.Activity
vals.Add(e.Result.LongErrorMessage); vals.Add(e.Result.LongErrorMessage);
} }
CreateLogEntry(new ActivityLogEntry await CreateLogEntry(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name), Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
Type = NotificationType.TaskFailed.ToString(), Type = NotificationType.TaskFailed.ToString(),
@ -472,11 +473,11 @@ namespace Emby.Server.Implementations.Activity
} }
} }
private void CreateLogEntry(ActivityLogEntry entry) private async Task CreateLogEntry(ActivityLogEntry entry)
{ {
try try
{ {
_activityManager.Create(entry); await _activityManager.CreateAsync(entry);
} }
catch catch
{ {

View File

@ -1,9 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Activity; using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Events; using MediaBrowser.Model.Events;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Activity namespace Emby.Server.Implementations.Activity
@ -26,20 +27,38 @@ namespace Emby.Server.Implementations.Activity
_userManager = userManager; _userManager = userManager;
} }
public void Create(ActivityLogEntry entry) public async Task CreateAsync(ActivityLogEntry entry)
{ {
entry.Date = DateTime.UtcNow; entry.Date = DateTime.UtcNow;
_repo.Create(entry); await _repo.CreateAsync(entry);
EntryCreated?.Invoke(this, new GenericEventArgs<ActivityLogEntry>(entry)); EntryCreated?.Invoke(this, new GenericEventArgs<ActivityLogEntry>(entry));
} }
public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? startIndex, int? limit) public IEnumerable<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? startIndex, int? limit)
{ {
var result = _repo.GetActivityLogEntries(minDate, hasUserId, startIndex, limit); var result = _repo.GetActivityLogEntries();
foreach (var item in result.Items.Where(i => !i.UserId.Equals(Guid.Empty))) if (minDate.HasValue)
{
result = result.Where(x => x.Date >= minDate.Value);
}
if (hasUserId.HasValue)
{
result = result.Where(x => x.UserId != null && x.UserId != Guid.Empty);
}
if (startIndex.HasValue)
{
result = result.Where(x => x.Id >= startIndex.Value);
}
if (limit.HasValue)
{
result = result.Take(limit.Value);
}
// Add images for each user
foreach (var item in result)
{ {
var user = _userManager.GetUserById(item.UserId); var user = _userManager.GetUserById(item.UserId);
@ -50,12 +69,7 @@ namespace Emby.Server.Implementations.Activity
} }
} }
return result; return result.AsEnumerable();
}
public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit)
{
return GetActivityLogEntries(minDate, null, startIndex, limit);
} }
} }
} }

View File

@ -1,310 +1,37 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Emby.Server.Implementations.Data; using System.Threading.Tasks;
using MediaBrowser.Controller;
using MediaBrowser.Model.Activity; using MediaBrowser.Model.Activity;
using MediaBrowser.Model.IO; using Microsoft.EntityFrameworkCore;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
using SQLitePCL.pretty;
namespace Emby.Server.Implementations.Activity namespace Emby.Server.Implementations.Activity
{ {
public class ActivityRepository : BaseSqliteRepository, IActivityRepository public class ActivityRepository : DbContext, IActivityRepository
{ {
private readonly CultureInfo _usCulture = new CultureInfo("en-US"); protected string _dataDirPath;
protected IFileSystem FileSystem { get; private set; }
public ActivityRepository(ILoggerFactory loggerFactory, IServerApplicationPaths appPaths, IFileSystem fileSystem) public DbSet<ActivityLogEntry> ActivityLogs { get; set; }
: base(loggerFactory.CreateLogger(nameof(ActivityRepository)))
public ActivityRepository(string dataDirPath)
{ {
DbFilePath = Path.Combine(appPaths.DataPath, "activitylog.db"); _dataDirPath = dataDirPath;
FileSystem = fileSystem;
} }
public void Initialize() protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
try // Ensure the dir exists
{ Directory.CreateDirectory(_dataDirPath);
InitializeInternal();
}
catch (Exception ex)
{
Logger.LogError(ex, "Error loading database file. Will reset and retry.");
FileSystem.DeleteFile(DbFilePath); optionsBuilder.UseSqlite($"Filename={Path.Combine(_dataDirPath, "activitylog.sqlite.db")}");
InitializeInternal();
}
} }
private void InitializeInternal() public async Task CreateAsync(ActivityLogEntry entry)
{ {
using (var connection = CreateConnection()) await ActivityLogs.AddAsync(entry);
{ await SaveChangesAsync();
RunDefaultInitialization(connection);
connection.RunQueries(new[]
{
"create table if not exists ActivityLog (Id INTEGER PRIMARY KEY, Name TEXT NOT NULL, Overview TEXT, ShortOverview TEXT, Type TEXT NOT NULL, ItemId TEXT, UserId TEXT, DateCreated DATETIME NOT NULL, LogSeverity TEXT NOT NULL)",
"drop index if exists idx_ActivityLogEntries"
});
TryMigrate(connection);
}
} }
private void TryMigrate(ManagedConnection connection) public IQueryable<ActivityLogEntry> GetActivityLogEntries()
{ => ActivityLogs;
try
{
if (TableExists(connection, "ActivityLogEntries"))
{
connection.RunQueries(new[]
{
"INSERT INTO ActivityLog (Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) SELECT Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity FROM ActivityLogEntries",
"drop table if exists ActivityLogEntries"
});
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Error migrating activity log database");
}
}
private const string BaseActivitySelectText = "select Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity from ActivityLog";
public void Create(ActivityLogEntry entry)
{
if (entry == null)
{
throw new ArgumentNullException(nameof(entry));
}
using (WriteLock.Write())
using (var connection = CreateConnection())
{
connection.RunInTransaction(db =>
{
using (var statement = db.PrepareStatement("insert into ActivityLog (Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)"))
{
statement.TryBind("@Name", entry.Name);
statement.TryBind("@Overview", entry.Overview);
statement.TryBind("@ShortOverview", entry.ShortOverview);
statement.TryBind("@Type", entry.Type);
statement.TryBind("@ItemId", entry.ItemId);
if (entry.UserId.Equals(Guid.Empty))
{
statement.TryBindNull("@UserId");
}
else
{
statement.TryBind("@UserId", entry.UserId.ToString("N"));
}
statement.TryBind("@DateCreated", entry.Date.ToDateTimeParamValue());
statement.TryBind("@LogSeverity", entry.Severity.ToString());
statement.MoveNext();
}
}, TransactionMode);
}
}
public void Update(ActivityLogEntry entry)
{
if (entry == null)
{
throw new ArgumentNullException(nameof(entry));
}
using (WriteLock.Write())
using (var connection = CreateConnection())
{
connection.RunInTransaction(db =>
{
using (var statement = db.PrepareStatement("Update ActivityLog set Name=@Name,Overview=@Overview,ShortOverview=@ShortOverview,Type=@Type,ItemId=@ItemId,UserId=@UserId,DateCreated=@DateCreated,LogSeverity=@LogSeverity where Id=@Id"))
{
statement.TryBind("@Id", entry.Id);
statement.TryBind("@Name", entry.Name);
statement.TryBind("@Overview", entry.Overview);
statement.TryBind("@ShortOverview", entry.ShortOverview);
statement.TryBind("@Type", entry.Type);
statement.TryBind("@ItemId", entry.ItemId);
if (entry.UserId.Equals(Guid.Empty))
{
statement.TryBindNull("@UserId");
}
else
{
statement.TryBind("@UserId", entry.UserId.ToString("N"));
}
statement.TryBind("@DateCreated", entry.Date.ToDateTimeParamValue());
statement.TryBind("@LogSeverity", entry.Severity.ToString());
statement.MoveNext();
}
}, TransactionMode);
}
}
public QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? startIndex, int? limit)
{
using (WriteLock.Read())
using (var connection = CreateConnection(true))
{
var commandText = BaseActivitySelectText;
var whereClauses = new List<string>();
if (minDate.HasValue)
{
whereClauses.Add("DateCreated>=@DateCreated");
}
if (hasUserId.HasValue)
{
if (hasUserId.Value)
{
whereClauses.Add("UserId not null");
}
else
{
whereClauses.Add("UserId is null");
}
}
var whereTextWithoutPaging = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
if (startIndex.HasValue && startIndex.Value > 0)
{
var pagingWhereText = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLog {0} ORDER BY DateCreated DESC LIMIT {1})",
pagingWhereText,
startIndex.Value.ToString(_usCulture)));
}
var whereText = whereClauses.Count == 0 ?
string.Empty :
" where " + string.Join(" AND ", whereClauses.ToArray());
commandText += whereText;
commandText += " ORDER BY DateCreated DESC";
if (limit.HasValue)
{
commandText += " LIMIT " + limit.Value.ToString(_usCulture);
}
var statementTexts = new List<string>();
statementTexts.Add(commandText);
statementTexts.Add("select count (Id) from ActivityLog" + whereTextWithoutPaging);
return connection.RunInTransaction(db =>
{
var list = new List<ActivityLogEntry>();
var result = new QueryResult<ActivityLogEntry>();
var statements = PrepareAllSafe(db, statementTexts).ToList();
using (var statement = statements[0])
{
if (minDate.HasValue)
{
statement.TryBind("@DateCreated", minDate.Value.ToDateTimeParamValue());
}
foreach (var row in statement.ExecuteQuery())
{
list.Add(GetEntry(row));
}
}
using (var statement = statements[1])
{
if (minDate.HasValue)
{
statement.TryBind("@DateCreated", minDate.Value.ToDateTimeParamValue());
}
result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
}
result.Items = list.ToArray();
return result;
}, ReadTransactionMode);
}
}
private static ActivityLogEntry GetEntry(IReadOnlyList<IResultSetValue> reader)
{
var index = 0;
var info = new ActivityLogEntry
{
Id = reader[index].ToInt64()
};
index++;
if (reader[index].SQLiteType != SQLiteType.Null)
{
info.Name = reader[index].ToString();
}
index++;
if (reader[index].SQLiteType != SQLiteType.Null)
{
info.Overview = reader[index].ToString();
}
index++;
if (reader[index].SQLiteType != SQLiteType.Null)
{
info.ShortOverview = reader[index].ToString();
}
index++;
if (reader[index].SQLiteType != SQLiteType.Null)
{
info.Type = reader[index].ToString();
}
index++;
if (reader[index].SQLiteType != SQLiteType.Null)
{
info.ItemId = reader[index].ToString();
}
index++;
if (reader[index].SQLiteType != SQLiteType.Null)
{
info.UserId = new Guid(reader[index].ToString());
}
index++;
info.Date = reader[index].ReadDateTime();
index++;
if (reader[index].SQLiteType != SQLiteType.Null)
{
info.Severity = (LogLevel)Enum.Parse(typeof(LogLevel), reader[index].ToString(), true);
}
return info;
}
} }
} }

View File

@ -709,7 +709,7 @@ namespace Emby.Server.Implementations
} }
} }
public void Init() public async Task InitAsync()
{ {
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber; HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber; HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@ -739,7 +739,7 @@ namespace Emby.Server.Implementations
SetHttpLimit(); SetHttpLimit();
RegisterResources(); await RegisterResourcesAsync();
FindParts(); FindParts();
} }
@ -754,7 +754,7 @@ namespace Emby.Server.Implementations
/// <summary> /// <summary>
/// Registers resources that classes will depend on /// Registers resources that classes will depend on
/// </summary> /// </summary>
protected void RegisterResources() protected async Task RegisterResourcesAsync()
{ {
RegisterSingleInstance(ConfigurationManager); RegisterSingleInstance(ConfigurationManager);
RegisterSingleInstance<IApplicationHost>(this); RegisterSingleInstance<IApplicationHost>(this);
@ -931,7 +931,7 @@ namespace Emby.Server.Implementations
EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager); EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager);
RegisterSingleInstance(EncodingManager); RegisterSingleInstance(EncodingManager);
var activityLogRepo = GetActivityLogRepository(); var activityLogRepo = await GetActivityLogRepositoryAsync();
RegisterSingleInstance(activityLogRepo); RegisterSingleInstance(activityLogRepo);
RegisterSingleInstance<IActivityManager>(new ActivityManager(LoggerFactory, activityLogRepo, UserManager)); RegisterSingleInstance<IActivityManager>(new ActivityManager(LoggerFactory, activityLogRepo, UserManager));
@ -1146,11 +1146,11 @@ namespace Emby.Server.Implementations
return repo; return repo;
} }
private IActivityRepository GetActivityLogRepository() private async Task<IActivityRepository> GetActivityLogRepositoryAsync()
{ {
var repo = new ActivityRepository(LoggerFactory, ServerConfigurationManager.ApplicationPaths, FileSystemManager); var repo = new ActivityRepository(ServerConfigurationManager.ApplicationPaths.DataPath);
repo.Initialize(); await repo.Database.EnsureCreatedAsync();
return repo; return repo;
} }

View File

@ -22,6 +22,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.0" />
<PackageReference Include="ServiceStack.Text.Core" Version="5.4.0" /> <PackageReference Include="ServiceStack.Text.Core" Version="5.4.0" />
<PackageReference Include="sharpcompress" Version="0.22.0" /> <PackageReference Include="sharpcompress" Version="0.22.0" />
<PackageReference Include="SimpleInjector" Version="4.4.2" /> <PackageReference Include="SimpleInjector" Version="4.4.2" />

View File

@ -99,7 +99,7 @@ namespace Jellyfin.Server
new SystemEvents(), new SystemEvents(),
new NetworkManager(_loggerFactory, environmentInfo))) new NetworkManager(_loggerFactory, environmentInfo)))
{ {
appHost.Init(); await appHost.InitAsync();
appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager); appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager);
@ -108,7 +108,6 @@ namespace Jellyfin.Server
await appHost.RunStartupTasks(); await appHost.RunStartupTasks();
// TODO: read input for a stop command // TODO: read input for a stop command
try try
{ {
// Block main thread until shutdown // Block main thread until shutdown
@ -167,7 +166,6 @@ namespace Jellyfin.Server
{ {
Directory.CreateDirectory(programDataPath); Directory.CreateDirectory(programDataPath);
} }
string configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR"); string configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR");
if (string.IsNullOrEmpty(configDir)) if (string.IsNullOrEmpty(configDir))
{ {

View File

@ -839,7 +839,7 @@ namespace MediaBrowser.Api.Library
{ {
try try
{ {
_activityManager.Create(new ActivityLogEntry _activityManager.CreateAsync(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name), Name = string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name),
Type = "UserDownloadingContent", Type = "UserDownloadingContent",

View File

@ -131,7 +131,7 @@ namespace MediaBrowser.Common
/// <summary> /// <summary>
/// Inits this instance. /// Inits this instance.
/// </summary> /// </summary>
void Init(); Task InitAsync();
/// <summary> /// <summary>
/// Creates the instance. /// Creates the instance.

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using MediaBrowser.Model.Events; using MediaBrowser.Model.Events;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Model.Activity namespace MediaBrowser.Model.Activity
{ {
@ -8,10 +9,8 @@ namespace MediaBrowser.Model.Activity
{ {
event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated; event EventHandler<GenericEventArgs<ActivityLogEntry>> EntryCreated;
void Create(ActivityLogEntry entry); Task CreateAsync(ActivityLogEntry entry);
QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit); IEnumerable<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? x, int? y);
QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? x, int? y);
} }
} }

View File

@ -1,12 +1,12 @@
using System; using System.Linq;
using MediaBrowser.Model.Querying; using System.Threading.Tasks;
namespace MediaBrowser.Model.Activity namespace MediaBrowser.Model.Activity
{ {
public interface IActivityRepository public interface IActivityRepository
{ {
void Create(ActivityLogEntry entry); Task CreateAsync(ActivityLogEntry entry);
QueryResult<ActivityLogEntry> GetActivityLogEntries(DateTime? minDate, bool? z, int? startIndex, int? limit); IQueryable<ActivityLogEntry> GetActivityLogEntries();
} }
} }