Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IDalamudConfigReader and early Analytics system #1547

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions Dalamud/Configuration/DalamudConfigReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Dalamud.Configuration.Internal;
using Dalamud.Configuration.Internal.Types;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Plugin.Services;
using Dalamud.Utility;

namespace Dalamud.Configuration;

/// <summary>
/// An implementation of <see cref="IDalamudConfigReader"/>.
/// </summary>
[ServiceManager.ScopedService]
[PluginInterface]
#pragma warning disable SA1015
[ResolveVia<IDalamudConfigReader>]
#pragma warning restore SA1015
internal class DalamudConfigReader : IServiceType, IDalamudConfigReader
{
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration dalamudConfiguration = Service<DalamudConfiguration>.Get();

private readonly LocalPlugin plugin;

/// <summary>
/// Initializes a new instance of the <see cref="DalamudConfigReader"/> class.
/// </summary>
/// <param name="plugin">The LocalPlugin this config reader is for. Used for certain per-plugin settings managed
/// by Dalamud.</param>
internal DalamudConfigReader(LocalPlugin plugin)
{
this.plugin = plugin;
}

/// <inheritdoc />
public PluginAnalyticsConsent PluginAnalyticsConsent => this.dalamudConfiguration.PluginAnalyticsConsent;

/// <inheritdoc />
public string PluginAnalyticsId
{
get
{
var analyticsId = this.PluginAnalyticsConsent == PluginAnalyticsConsent.OptedOut
? null
: this.dalamudConfiguration.PluginAnalyticsId;

return Hash.GetSha256Base64Hash($"{this.plugin.InternalName}#{analyticsId}");
}
}

/// <inheritdoc/>
public bool IsMbCollect => this.dalamudConfiguration.IsMbCollect;

/// <inheritdoc/>
public bool DisableRmtFiltering => this.dalamudConfiguration.DisableRmtFiltering;

/// <inheritdoc/>
public bool IsAntiAntiDebugEnabled => this.dalamudConfiguration.IsAntiAntiDebugEnabled;

/// <inheritdoc />
public bool EnablePluginUISoundEffects => this.dalamudConfiguration.EnablePluginUISoundEffects;

/// <inheritdoc />
public bool AutoUpdatePlugins => this.dalamudConfiguration.AutoUpdatePlugins;

/// <inheritdoc/>
public bool DoButtonsSystemMenu => this.dalamudConfiguration.DoButtonsSystemMenu;

/// <inheritdoc/>
public bool IsResumeGameAfterPluginLoad => this.dalamudConfiguration.IsResumeGameAfterPluginLoad;
}
11 changes: 11 additions & 0 deletions Dalamud/Configuration/Internal/DalamudConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Runtime.InteropServices;

using Dalamud.Configuration.Internal.Types;
using Dalamud.Game.Text;
using Dalamud.Interface;
using Dalamud.Interface.FontIdentifier;
Expand Down Expand Up @@ -464,6 +465,16 @@ public string EffectiveLanguage
/// </summary>
public PluginInstallerOpenKind PluginInstallerOpen { get; set; } = PluginInstallerOpenKind.AllPlugins;

/// <summary>
/// Gets or sets the user's preference towards plugin analytics.
/// </summary>
public PluginAnalyticsConsent PluginAnalyticsConsent { get; set; } = PluginAnalyticsConsent.Ask;

/// <summary>
/// Gets or sets the installation's current Plugin Analytics ID. This can be reset by the user at any time.
/// </summary>
public string PluginAnalyticsId { get; set; } = Guid.NewGuid().ToString();

/// <summary>
/// Load a configuration from the provided path.
/// </summary>
Expand Down
29 changes: 29 additions & 0 deletions Dalamud/Configuration/Internal/Types/PluginAnalyticsConsent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Dalamud.Interface.Internal.Windows.Settings.Widgets;

namespace Dalamud.Configuration.Internal.Types;

/// <summary>
/// An enum defining possible states for the analytics settings exposed to plugins.
/// </summary>
public enum PluginAnalyticsConsent
{
/// <summary>
/// Indicates that plugin developers should *not* enable any analytics functionality, and should not request to
/// turn them on.
/// </summary>
[SettingsAnnotation("Opted Out", "Request plugins not collect analytics.")]
OptedOut,

/// <summary>
/// Indicates that plugin developers should ask the user before collecting any analytics on them.
/// </summary>
[SettingsAnnotation("Ask Before Collecting", "Allow analytics, but request plugins ask before collecting any.")]
Ask,

/// <summary>
/// Indicates that plugins developers are permitted to enable analytics without prompting the user for permission,
/// should they so choose.
/// </summary>
[SettingsAnnotation("Opted In", "Automatically allow plugins to collect analytics.")]
OptedIn,
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
using System.Diagnostics.CodeAnalysis;

using CheapLoc;
using Dalamud.Configuration.Internal;
using Dalamud.Configuration.Internal.Types;
using Dalamud.Game.Text;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.Windows.Settings.Widgets;
using Dalamud.Interface.Utility;

namespace Dalamud.Interface.Internal.Windows.Settings.Tabs;

Expand Down Expand Up @@ -87,6 +92,33 @@ public class SettingsTabGeneral : SettingsTab
Loc.Localize("DalamudSettingDoMbCollectHint", "Anonymously provide data about in-game economics to Universalis when browsing the market board. This data can't be tied to you in any way and everyone benefits!"),
c => c.IsMbCollect,
(v, c) => c.IsMbCollect = v),

new SettingsEntry<PluginAnalyticsConsent>(
Loc.Localize("DalamudSettingPluginAnalyticsConsent", "Contribute Data to Plugin Analytics Systems"),
Loc.Localize("DalamudSettingPluginAnalyticsConsentHint", "This setting will allow certain plugins to collect analytics info on you, your playstyle, and how you use them. Certain plugins (e.g. custom repository plugins, those that provide crowdsourced information) may not respect this setting."),
c => c.PluginAnalyticsConsent,
(v, c) => { c.PluginAnalyticsConsent = v; }),

new ButtonSettingsEntry(
Loc.Localize("DalamudSettingResetPluginAnalyticsId", "Reset Analytics ID"),
Loc.Localize("DalamudSettingResetPluginAnalyticsIdHint", "Resets your Analytics ID to a new randomized value."),
() =>
{
var cfg = Service<DalamudConfiguration>.Get();
cfg.PluginAnalyticsId = Guid.NewGuid().ToString();
}),

new DynamicSettingsEntry(() =>
{
var analyticsId = Service<DalamudConfiguration>.Get().PluginAnalyticsId;

var rendered =
string.Format(Loc.Localize("DalamudSettingPluginAnalyticsId", "Your current Plugin Analytics ID: {0}"),
analyticsId);

ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, rendered);
ImGuiComponents.HelpMarker(Loc.Localize("DalamudSettingPluginAnalyticsIdDetails", "This analytics ID is never directly shared with plugins. Every installed plugin receives a unique analytics ID based on this value."));
}),
};

public override string Title => Loc.Localize("DalamudSettingsGeneral", "General");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace Dalamud.Interface.Internal.Windows.Settings.Widgets;

/// <summary>
/// A SettingsEntry designed for dynamic events that need to be evaluated once on every frame.
/// </summary>
public class DynamicSettingsEntry : SettingsEntry
{
private Action drawAction;

/// <summary>
/// Initializes a new instance of the <see cref="DynamicSettingsEntry"/> class.
/// </summary>
/// <param name="drawAction">The action to draw when called.</param>
public DynamicSettingsEntry(Action drawAction)
{
this.drawAction = drawAction;
}

/// <inheritdoc/>
public override void Load()
{
// ignore
}

/// <inheritdoc/>
public override void Save()
{
// ignore;
}

/// <inheritdoc/>
public override void Draw()
{
this.drawAction.Invoke();
}
}
48 changes: 48 additions & 0 deletions Dalamud/Plugin/Services/IDalamudConfigReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Dalamud.Configuration.Internal;
using Dalamud.Configuration.Internal.Types;

namespace Dalamud.Plugin.Services;

/// <summary>
/// A service for giving plugins access to select Dalamud settings.
/// </summary>
public interface IDalamudConfigReader
{
/// <summary>
/// Gets a value indicating whether the user has permitted plugins to collect analytics on them. Plugins should
/// respect this setting *as well as* offer individual opt outs if it makes sense.
/// </summary>
public PluginAnalyticsConsent PluginAnalyticsConsent { get; }

/// <summary>
/// Gets an opaque string intended for use as an analytics ID for plugins. This value is derived from a persistent
/// ID stored in Dalamud's configuration, and is unique per plugin requesting it.
/// </summary>
/// <remarks>
/// If the user has requested to disable analytics, this property will still return a valid ID that will be shared
/// across <em>all</em> users of the plugin with analytics disabled.
/// </remarks>
public string PluginAnalyticsId { get; }


/// <inheritdoc cref="DalamudConfiguration.IsMbCollect"/>
public bool IsMbCollect { get; }

/// <inheritdoc cref="DalamudConfiguration.DisableRmtFiltering"/>
public bool DisableRmtFiltering { get; }

/// <inheritdoc cref="DalamudConfiguration.IsAntiAntiDebugEnabled"/>
public bool IsAntiAntiDebugEnabled { get; }

/// <inheritdoc cref="DalamudConfiguration.EnablePluginUISoundEffects"/>
public bool EnablePluginUISoundEffects { get; }

/// <inheritdoc cref="DalamudConfiguration.AutoUpdatePlugins"/>
public bool AutoUpdatePlugins { get; }

/// <inheritdoc cref="DalamudConfiguration.DoButtonsSystemMenu"/>
public bool DoButtonsSystemMenu { get; }

/// <inheritdoc cref="DalamudConfiguration.IsResumeGameAfterPluginLoad"/>
public bool IsResumeGameAfterPluginLoad { get; }
}
13 changes: 13 additions & 0 deletions Dalamud/Utility/Hash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,18 @@ internal static string GetSha256Hash(byte[] buffer)
return ByteArrayToString(hash);
}

/// <summary>
/// Get the SHA-256 hash (as Base64) of a string of text.
/// </summary>
/// <param name="text">The text to hash.</param>
/// <returns>The computed hash, in Base64.</returns>
internal static string GetSha256Base64Hash(string text)
{
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
var hash = SHA256.HashData(bytes);

return Convert.ToBase64String(hash);
}

private static string ByteArrayToString(byte[] ba) => BitConverter.ToString(ba).Replace("-", string.Empty);
}
Loading