Browse Source

refactor models and remove cache run mode

v4/state-cache-providers
Quin Lynch 3 years ago
parent
commit
59c334ac60
14 changed files with 201 additions and 211 deletions
  1. +0
    -2
      src/Discord.Net.Core/Cache/ICached.cs
  2. +1
    -1
      src/Discord.Net.Core/Cache/Models/Users/IMemberModel.cs
  3. +0
    -1
      src/Discord.Net.Core/Cache/Models/Users/IThreadMemberModel.cs
  4. +2
    -2
      src/Discord.Net.Rest/API/Common/GuildMember.cs
  5. +0
    -1
      src/Discord.Net.Rest/API/Common/ThreadMember.cs
  6. +0
    -21
      src/Discord.Net.WebSocket/Cache/CacheRunMode.cs
  7. +57
    -19
      src/Discord.Net.WebSocket/Cache/DefaultConcurrentCacheProvider.cs
  8. +14
    -6
      src/Discord.Net.WebSocket/Cache/ICacheProvider.cs
  9. +33
    -37
      src/Discord.Net.WebSocket/ClientStateManager.Experiment.cs
  10. +26
    -31
      src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
  11. +32
    -38
      src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs
  12. +14
    -20
      src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs
  13. +14
    -15
      src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs
  14. +8
    -17
      src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs

+ 0
- 2
src/Discord.Net.Core/Cache/ICached.cs View File

@@ -11,8 +11,6 @@ namespace Discord
void Update(TType model); void Update(TType model);


TType ToModel(); TType ToModel();

TResult ToModel<TResult>() where TResult : TType, new();
} }


public interface ICached public interface ICached


+ 1
- 1
src/Discord.Net.Core/Cache/Models/Users/IMemberModel.cs View File

@@ -12,7 +12,7 @@ namespace Discord
string Nickname { get; set; } string Nickname { get; set; }
string GuildAvatar { get; set; } string GuildAvatar { get; set; }
ulong[] Roles { get; set; } ulong[] Roles { get; set; }
DateTimeOffset JoinedAt { get; set; }
DateTimeOffset? JoinedAt { get; set; }
DateTimeOffset? PremiumSince { get; set; } DateTimeOffset? PremiumSince { get; set; }
bool IsDeaf { get; set; } bool IsDeaf { get; set; }
bool IsMute { get; set; } bool IsMute { get; set; }


+ 0
- 1
src/Discord.Net.Core/Cache/Models/Users/IThreadMemberModel.cs View File

@@ -9,7 +9,6 @@ namespace Discord
public interface IThreadMemberModel : IEntityModel<ulong> public interface IThreadMemberModel : IEntityModel<ulong>
{ {
ulong? ThreadId { get; set; } ulong? ThreadId { get; set; }
ulong? UserId { get; set; }
DateTimeOffset JoinedAt { get; set; } DateTimeOffset JoinedAt { get; set; }
} }
} }

+ 2
- 2
src/Discord.Net.Rest/API/Common/GuildMember.cs View File

@@ -39,8 +39,8 @@ namespace Discord.API
get => Roles.GetValueOrDefault(Array.Empty<ulong>()); set => throw new NotSupportedException(); get => Roles.GetValueOrDefault(Array.Empty<ulong>()); set => throw new NotSupportedException();
} }


DateTimeOffset IMemberModel.JoinedAt {
get => JoinedAt.GetValueOrDefault(); set => throw new NotSupportedException();
DateTimeOffset? IMemberModel.JoinedAt {
get => JoinedAt.ToNullable(); set => throw new NotSupportedException();
} }


DateTimeOffset? IMemberModel.PremiumSince { DateTimeOffset? IMemberModel.PremiumSince {


+ 0
- 1
src/Discord.Net.Rest/API/Common/ThreadMember.cs View File

@@ -15,7 +15,6 @@ namespace Discord.API
public DateTimeOffset JoinTimestamp { get; set; } public DateTimeOffset JoinTimestamp { get; set; }


ulong? IThreadMemberModel.ThreadId { get => ThreadId.ToNullable(); set => throw new NotSupportedException(); } ulong? IThreadMemberModel.ThreadId { get => ThreadId.ToNullable(); set => throw new NotSupportedException(); }
ulong? IThreadMemberModel.UserId { get => UserId.ToNullable(); set => throw new NotSupportedException(); }
DateTimeOffset IThreadMemberModel.JoinedAt { get => JoinTimestamp; set => throw new NotSupportedException(); } DateTimeOffset IThreadMemberModel.JoinedAt { get => JoinTimestamp; set => throw new NotSupportedException(); }
ulong IEntityModel<ulong>.Id { get => UserId.GetValueOrDefault(0); set => throw new NotSupportedException(); } ulong IEntityModel<ulong>.Id { get => UserId.GetValueOrDefault(0); set => throw new NotSupportedException(); }
} }


+ 0
- 21
src/Discord.Net.WebSocket/Cache/CacheRunMode.cs View File

@@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord.WebSocket
{
public enum CacheRunMode
{
/// <summary>
/// The cache should preform a synchronous cache lookup.
/// </summary>
Sync,

/// <summary>
/// The cache should preform either a <see cref="Sync"/> or asynchronous cache lookup.
/// </summary>
Async
}
}

+ 57
- 19
src/Discord.Net.WebSocket/Cache/DefaultConcurrentCacheProvider.cs View File

@@ -12,6 +12,16 @@ namespace Discord.WebSocket
private readonly ConcurrentDictionary<Type, object> _storeCache = new(); private readonly ConcurrentDictionary<Type, object> _storeCache = new();
private readonly ConcurrentDictionary<object, object> _subStoreCache = new(); private readonly ConcurrentDictionary<object, object> _subStoreCache = new();


private readonly Dictionary<Type, Type> _models = new()
{
{ typeof(IUserModel), typeof(API.User) },
{ typeof(ICurrentUserModel), typeof(API.CurrentUser) },
{ typeof(IMemberModel), typeof(API.GuildMember) },
{ typeof(IThreadMemberModel), typeof(API.ThreadMember)},
{ typeof(IPresenceModel), typeof(API.Presence)},
{ typeof(IActivityModel), typeof(API.Game)}
};

private class DefaultEntityStore<TModel, TId> : IEntityStore<TModel, TId> private class DefaultEntityStore<TModel, TId> : IEntityStore<TModel, TId>
where TModel : IEntityModel<TId> where TModel : IEntityModel<TId>
where TId : IEquatable<TId> where TId : IEquatable<TId>
@@ -23,44 +33,72 @@ namespace Discord.WebSocket
_cache = cache; _cache = cache;
} }


public ValueTask AddOrUpdateAsync(TModel model, CacheRunMode runmode)
public TModel Get(TId id)
{ {
_cache.AddOrUpdate(model.Id, model, (_, __) => model);
if (_cache.TryGetValue(id, out var model))
return model;
return default; return default;
} }

public ValueTask AddOrUpdateBatchAsync(IEnumerable<TModel> models, CacheRunMode runmode)
public IEnumerable<TModel> GetAll()
{
return _cache.Select(x => x.Value);
}
public void AddOrUpdate(TModel model)
{
_cache.AddOrUpdate(model.Id, model, (_, __) => model);
}
public void AddOrUpdateBatch(IEnumerable<TModel> models)
{ {
foreach (var model in models) foreach (var model in models)
_cache.AddOrUpdate(model.Id, model, (_, __) => model); _cache.AddOrUpdate(model.Id, model, (_, __) => model);
return default;
}
public void Remove(TId id)
{
_cache.TryRemove(id, out _);
}
public void PurgeAll()
{
_cache.Clear();
} }


public IAsyncEnumerable<TModel> GetAllAsync(CacheRunMode runmode)
ValueTask<TModel> IEntityStore<TModel, TId>.GetAsync(TId id) => new ValueTask<TModel>(Get(id));
IAsyncEnumerable<TModel> IEntityStore<TModel, TId>.GetAllAsync()
{ {
var coll = _cache.Select(x => x.Value).GetEnumerator();
return AsyncEnumerable.Create((_) => AsyncEnumerator.Create(
() => new ValueTask<bool>(coll.MoveNext()),
() => coll.Current,
() => new ValueTask()));
var enumerator = GetAll().GetEnumerator();
return AsyncEnumerable.Create((cancellationToken)
=> AsyncEnumerator.Create(
() => new ValueTask<bool>(enumerator.MoveNext()),
() => enumerator.Current,
() => new ValueTask())
);
} }
public ValueTask<TModel> GetAsync(TId id, CacheRunMode runmode)
ValueTask IEntityStore<TModel, TId>.AddOrUpdateAsync(TModel model)
{ {
if (_cache.TryGetValue(id, out var model))
return new ValueTask<TModel>(model);
AddOrUpdate(model);
return default; return default;
} }
public ValueTask RemoveAsync(TId id, CacheRunMode runmode)
ValueTask IEntityStore<TModel, TId>.AddOrUpdateBatchAsync(IEnumerable<TModel> models)
{ {
_cache.TryRemove(id, out _);
AddOrUpdateBatch(models);
return default; return default;
} }

public ValueTask PurgeAllAsync(CacheRunMode runmode)
ValueTask IEntityStore<TModel, TId>.RemoveAsync(TId id)
{ {
_cache.Clear();
Remove(id);
return default; return default;
} }
ValueTask IEntityStore<TModel, TId>.PurgeAllAsync()
{
PurgeAll();
return default;
}
}

public Type GetModel<TInterface>()
{
if (_models.TryGetValue(typeof(TInterface), out var t))
return t;
return null;
} }


public virtual ValueTask<IEntityStore<TModel, TId>> GetStoreAsync<TModel, TId>() public virtual ValueTask<IEntityStore<TModel, TId>> GetStoreAsync<TModel, TId>()


+ 14
- 6
src/Discord.Net.WebSocket/Cache/ICacheProvider.cs View File

@@ -8,6 +8,8 @@ namespace Discord.WebSocket
{ {
public interface ICacheProvider public interface ICacheProvider
{ {
Type GetModel<TModelInterface>();

ValueTask<IEntityStore<TModel, TId>> GetStoreAsync<TModel, TId>() ValueTask<IEntityStore<TModel, TId>> GetStoreAsync<TModel, TId>()
where TModel : IEntityModel<TId> where TModel : IEntityModel<TId>
where TId : IEquatable<TId>; where TId : IEquatable<TId>;
@@ -21,11 +23,17 @@ namespace Discord.WebSocket
where TModel : IEntityModel<TId> where TModel : IEntityModel<TId>
where TId : IEquatable<TId> where TId : IEquatable<TId>
{ {
ValueTask<TModel> GetAsync(TId id, CacheRunMode runmode);
IAsyncEnumerable<TModel> GetAllAsync(CacheRunMode runmode);
ValueTask AddOrUpdateAsync(TModel model, CacheRunMode runmode);
ValueTask AddOrUpdateBatchAsync(IEnumerable<TModel> models, CacheRunMode runmode);
ValueTask RemoveAsync(TId id, CacheRunMode runmode);
ValueTask PurgeAllAsync(CacheRunMode runmode);
ValueTask<TModel> GetAsync(TId id);
TModel Get(TId id);
IAsyncEnumerable<TModel> GetAllAsync();
IEnumerable<TModel> GetAll();
ValueTask AddOrUpdateAsync(TModel model);
void AddOrUpdate(TModel model);
ValueTask AddOrUpdateBatchAsync(IEnumerable<TModel> models);
void AddOrUpdateBatch(IEnumerable<TModel> models);
ValueTask RemoveAsync(TId id);
void Remove(TId id);
ValueTask PurgeAllAsync();
void PurgeAll();
} }
} }

+ 33
- 37
src/Discord.Net.WebSocket/ClientStateManager.Experiment.cs View File

@@ -92,28 +92,6 @@ namespace Discord.WebSocket
} }
} }


private TResult RunOrThrowValueTask<TResult>(ValueTask<TResult> t)
{
if (_allowSyncWaits)
{
return t.GetAwaiter().GetResult();
}
else if (t.IsCompleted)
return t.Result;
else
throw new InvalidOperationException("Cannot run asynchronous value task in synchronous context");
}

private void RunOrThrowValueTask(ValueTask t)
{
if (_allowSyncWaits)
{
t.GetAwaiter().GetResult();
}
else if (!t.IsCompleted)
throw new InvalidOperationException("Cannot run asynchronous value task in synchronous context");
}

public async ValueTask InitializeAsync() public async ValueTask InitializeAsync()
{ {
_store ??= await _cacheProvider.GetStoreAsync<TModel, TId>().ConfigureAwait(false); _store ??= await _cacheProvider.GetStoreAsync<TModel, TId>().ConfigureAwait(false);
@@ -137,7 +115,7 @@ namespace Discord.WebSocket
return entity; return entity;
} }


var model = RunOrThrowValueTask(_store.GetAsync(id, CacheRunMode.Sync));
var model = _store.Get(id);


if (model != null) if (model != null)
{ {
@@ -156,7 +134,7 @@ namespace Discord.WebSocket
return entity; return entity;
} }


var model = await _store.GetAsync(id, CacheRunMode.Async).ConfigureAwait(false);
var model = await _store.GetAsync(id).ConfigureAwait(false);


if (model != null) if (model != null)
{ {
@@ -175,7 +153,7 @@ namespace Discord.WebSocket


public IEnumerable<TEntity> GetAll() public IEnumerable<TEntity> GetAll()
{ {
var models = RunOrThrowValueTask(_store.GetAllAsync(CacheRunMode.Sync).ToArrayAsync());
var models = _store.GetAll();
return models.Select(x => return models.Select(x =>
{ {
var entity = _entityBuilder(x); var entity = _entityBuilder(x);
@@ -186,7 +164,7 @@ namespace Discord.WebSocket


public async IAsyncEnumerable<TEntity> GetAllAsync() public async IAsyncEnumerable<TEntity> GetAllAsync()
{ {
await foreach(var model in _store.GetAllAsync(CacheRunMode.Async))
await foreach(var model in _store.GetAllAsync())
{ {
var entity = _entityBuilder(model); var entity = _entityBuilder(model);
_references.TryAdd(model.Id, new CacheReference<TEntity>(entity)); _references.TryAdd(model.Id, new CacheReference<TEntity>(entity));
@@ -212,13 +190,13 @@ namespace Discord.WebSocket
return (TEntity)entity; return (TEntity)entity;


var model = valueFactory(id); var model = valueFactory(id);
await AddOrUpdateAsync(model);
await AddOrUpdateAsync(model).ConfigureAwait(false);
return _entityBuilder(model); return _entityBuilder(model);
} }


public void AddOrUpdate(TModel model) public void AddOrUpdate(TModel model)
{ {
RunOrThrowValueTask(_store.AddOrUpdateAsync(model, CacheRunMode.Sync));
_store.AddOrUpdate(model);
if (TryGetReference(model.Id, out var reference)) if (TryGetReference(model.Id, out var reference))
reference.Update(model); reference.Update(model);
} }
@@ -227,14 +205,13 @@ namespace Discord.WebSocket
{ {
if (TryGetReference(model.Id, out var reference)) if (TryGetReference(model.Id, out var reference))
reference.Update(model); reference.Update(model);
return _store.AddOrUpdateAsync(model, CacheRunMode.Async);
return _store.AddOrUpdateAsync(model);
} }


public void BulkAddOrUpdate(IEnumerable<TModel> models) public void BulkAddOrUpdate(IEnumerable<TModel> models)
{ {
RunOrThrowValueTask(_store.AddOrUpdateBatchAsync(models, CacheRunMode.Sync));

foreach(var model in models)
_store.AddOrUpdateBatch(models);
foreach (var model in models)
{ {
if (_references.TryGetValue(model.Id, out var rf) && rf.Reference.TryGetTarget(out var entity)) if (_references.TryGetValue(model.Id, out var rf) && rf.Reference.TryGetTarget(out var entity))
entity.Update(model); entity.Update(model);
@@ -243,7 +220,7 @@ namespace Discord.WebSocket


public async ValueTask BulkAddOrUpdateAsync(IEnumerable<TModel> models) public async ValueTask BulkAddOrUpdateAsync(IEnumerable<TModel> models)
{ {
await _store.AddOrUpdateBatchAsync(models, CacheRunMode.Async).ConfigureAwait(false);
await _store.AddOrUpdateBatchAsync(models).ConfigureAwait(false);


foreach (var model in models) foreach (var model in models)
{ {
@@ -254,26 +231,26 @@ namespace Discord.WebSocket


public void Remove(TId id) public void Remove(TId id)
{ {
RunOrThrowValueTask(_store.RemoveAsync(id, CacheRunMode.Sync));
_store.Remove(id);
_references.TryRemove(id, out _); _references.TryRemove(id, out _);
} }


public ValueTask RemoveAsync(TId id) public ValueTask RemoveAsync(TId id)
{ {
_references.TryRemove(id, out _); _references.TryRemove(id, out _);
return _store.RemoveAsync(id, CacheRunMode.Async);
return _store.RemoveAsync(id);
} }


public void Purge() public void Purge()
{ {
RunOrThrowValueTask(_store.PurgeAllAsync(CacheRunMode.Sync));
_store.PurgeAll();
_references.Clear(); _references.Clear();
} }


public ValueTask PurgeAsync() public ValueTask PurgeAsync()
{ {
_references.Clear(); _references.Clear();
return _store.PurgeAllAsync(CacheRunMode.Async);
return _store.PurgeAllAsync();
} }


TEntity ILookupReferenceStore<TEntity, TId>.Get(TId id) => Get(id); TEntity ILookupReferenceStore<TEntity, TId>.Get(TId id) => Get(id);
@@ -380,5 +357,24 @@ namespace Discord.WebSocket
_threadMemberLock.Release(); _threadMemberLock.Release();
} }
} }

public ReferenceStore<SocketThreadUser, IThreadMemberModel, ulong, IThreadUser> GetThreadMemberStore(ulong threadId)
=> _threadMemberStores.TryGetValue(threadId, out var store) ? store : null;

public TModel GetModel<TModel, TFallback>()
where TFallback : class, TModel, new()
{
var type = _cacheProvider.GetModel<TModel>();

if (type != null)
{
if (!type.GetInterfaces().Contains(typeof(TModel)))
throw new InvalidOperationException($"Cannot use {type.Name} as a model for {typeof(TModel).Name}");

return (TModel)Activator.CreateInstance(type);
}
else
return new TFallback();
}
} }
} }

+ 26
- 31
src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs View File

@@ -74,7 +74,6 @@ namespace Discord.WebSocket
/// <inheritdoc /> /// <inheritdoc />
public bool? IsPending { get; private set; } public bool? IsPending { get; private set; }



/// <inheritdoc /> /// <inheritdoc />
public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks); public DateTimeOffset? JoinedAt => DateTimeUtils.FromTicks(_joinedAtTicks);
/// <summary> /// <summary>
@@ -159,7 +158,7 @@ namespace Discord.WebSocket
} }
internal void Update(MemberModel model) internal void Update(MemberModel model)
{ {
_joinedAtTicks = model.JoinedAt.UtcTicks;
_joinedAtTicks = model.JoinedAt.HasValue ? model.JoinedAt.Value.UtcTicks : null;
Nickname = model.Nickname; Nickname = model.Nickname;
GuildAvatarId = model.GuildAvatar; GuildAvatarId = model.GuildAvatar;
UpdateRoles(model.Roles); UpdateRoles(model.Roles);
@@ -232,6 +231,17 @@ namespace Discord.WebSocket


internal new SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser; internal new SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser;


public override void Dispose()
{
if (IsFreed)
return;

GC.SuppressFinalize(this);
Discord.StateManager.GetMemberStore(_guildId)?.RemoveReference(Id);
IsFreed = true;
}
~SocketGuildUser() => Dispose();

#endregion #endregion


#region IGuildUser #region IGuildUser
@@ -249,7 +259,7 @@ namespace Discord.WebSocket


#region Cache #region Cache


private struct CacheModel : MemberModel
private class CacheModel : MemberModel
{ {
public ulong Id { get; set; } public ulong Id { get; set; }
public string Nickname { get; set; } public string Nickname { get; set; }
@@ -258,7 +268,7 @@ namespace Discord.WebSocket


public ulong[] Roles { get; set; } public ulong[] Roles { get; set; }


public DateTimeOffset JoinedAt { get; set; }
public DateTimeOffset? JoinedAt { get; set; }


public DateTimeOffset? PremiumSince { get; set; } public DateTimeOffset? PremiumSince { get; set; }


@@ -271,40 +281,25 @@ namespace Discord.WebSocket
public DateTimeOffset? CommunicationsDisabledUntil { get; set; } public DateTimeOffset? CommunicationsDisabledUntil { get; set; }
} }
internal new MemberModel ToModel() internal new MemberModel ToModel()
=> ToModel<CacheModel>();

internal new TModel ToModel<TModel>() where TModel : MemberModel, new()
{ {
return new TModel
{
Id = Id,
CommunicationsDisabledUntil = TimedOutUntil,
GuildAvatar = GuildAvatarId,
IsDeaf = IsDeafened,
IsMute = IsMuted,
IsPending = IsPending,
JoinedAt = JoinedAt ?? DateTimeOffset.UtcNow, // review: nullable joined at here? should our model reflect this?
Nickname = Nickname,
PremiumSince = PremiumSince,
Roles = _roleIds.ToArray()
};
var model = Discord.StateManager.GetModel<MemberModel, CacheModel>();
model.Id = Id;
model.Nickname = Nickname;
model.GuildAvatar = GuildAvatarId;
model.Roles = _roleIds.ToArray();
model.JoinedAt = JoinedAt;
model.PremiumSince = PremiumSince;
model.IsDeaf = IsDeafened;
model.IsMute = IsMuted;
model.IsPending = IsPending;
model.CommunicationsDisabledUntil = TimedOutUntil;
return model;
} }


MemberModel ICached<MemberModel>.ToModel() MemberModel ICached<MemberModel>.ToModel()
=> ToModel(); => ToModel();


TResult ICached<MemberModel>.ToModel<TResult>()
=> ToModel<TResult>();

void ICached<MemberModel>.Update(MemberModel model) => Update(model); void ICached<MemberModel>.Update(MemberModel model) => Update(model);

public override void Dispose()
{
GC.SuppressFinalize(this);
Discord.StateManager.GetMemberStore(_guildId)?.RemoveReference(Id);
}
~SocketGuildUser() => Dispose();

#endregion #endregion
} }
} }

+ 32
- 38
src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs View File

@@ -112,7 +112,6 @@ namespace Discord.WebSocket
internal SocketPresence Clone() => MemberwiseClone() as SocketPresence; internal SocketPresence Clone() => MemberwiseClone() as SocketPresence;


~SocketPresence() => Dispose(); ~SocketPresence() => Dispose();

public void Dispose() public void Dispose()
{ {
if (IsFreed) if (IsFreed)
@@ -128,7 +127,7 @@ namespace Discord.WebSocket
} }


#region Cache #region Cache
private struct CacheModel : Model
private class CacheModel : Model
{ {
public UserStatus Status { get; set; } public UserStatus Status { get; set; }


@@ -187,48 +186,43 @@ namespace Discord.WebSocket
} }


internal Model ToModel() internal Model ToModel()
=> ToModel<CacheModel>();

internal TModel ToModel<TModel>() where TModel : Model, new()
{ {
return new TModel
var model = Discord.StateManager.GetModel<Model, CacheModel>();
model.Status = Status;
model.ActiveClients = ActiveClients.ToArray();
model.UserId = UserId;
model.GuildId = GuildId;
model.Activities = Activities.Select(x =>
{ {
Status = Status,
ActiveClients = ActiveClients.ToArray(),
UserId = UserId,
GuildId = GuildId,
Activities = Activities.Select(x =>
switch (x)
{
case Game game:
switch (game)
{
case RichGame richGame:
return richGame.ToModel<ActivityCacheModel>();
case SpotifyGame spotify:
return spotify.ToModel<ActivityCacheModel>();
case CustomStatusGame custom:
return custom.ToModel<ActivityCacheModel, EmojiCacheModel>();
case StreamingGame stream:
return stream.ToModel<ActivityCacheModel>();
}
break;
}

return new ActivityCacheModel
{ {
switch (x)
{
case Game game:
switch (game)
{
case RichGame richGame:
return richGame.ToModel<ActivityCacheModel>();
case SpotifyGame spotify:
return spotify.ToModel<ActivityCacheModel>();
case CustomStatusGame custom:
return custom.ToModel<ActivityCacheModel, EmojiCacheModel>();
case StreamingGame stream:
return stream.ToModel<ActivityCacheModel>();
}
break;
}

return new ActivityCacheModel
{
Name = x.Name,
Details = x.Details,
Flags = x.Flags,
Type = x.Type
};
}).ToArray(),
};
Name = x.Name,
Details = x.Details,
Flags = x.Flags,
Type = x.Type
};
}).ToArray();
return model;
} }


Model ICached<Model>.ToModel() => ToModel(); Model ICached<Model>.ToModel() => ToModel();
TResult ICached<Model>.ToModel<TResult>() => ToModel<TResult>();
void ICached<Model>.Update(Model model) => Update(model); void ICached<Model>.Update(Model model) => Update(model);
bool ICached.IsFreed => IsFreed; bool ICached.IsFreed => IsFreed;




+ 14
- 20
src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs View File

@@ -97,7 +97,7 @@ namespace Discord.WebSocket
} }


#region Cache #region Cache
private struct CacheModel : Model
private class CacheModel : Model
{ {
public bool? IsVerified { get; set; } public bool? IsVerified { get; set; }


@@ -125,29 +125,23 @@ namespace Discord.WebSocket
} }


internal new Model ToModel() internal new Model ToModel()
=> ToModel<CacheModel>();

internal new TModel ToModel<TModel>() where TModel : Model, new()
{ {
return new TModel
{
Avatar = AvatarId,
Discriminator = Discriminator,
Email = Email,
Flags = Flags,
Id = Id,
IsBot = IsBot,
IsMfaEnabled = IsMfaEnabled,
IsVerified = IsVerified,
Locale = Locale,
PremiumType = this.PremiumType,
PublicFlags = PublicFlags ?? UserProperties.None,
Username = Username
};
var model = Discord.StateManager.GetModel<Model, CacheModel>();
model.Avatar = AvatarId;
model.Discriminator = Discriminator;
model.Email = Email;
model.Flags = Flags;
model.IsBot = IsBot;
model.IsMfaEnabled = IsMfaEnabled;
model.Locale = Locale;
model.PremiumType = PremiumType;
model.PublicFlags = PublicFlags ?? UserProperties.None;
model.Username = Username;
model.Id = Id;
return model;
} }


Model ICached<Model>.ToModel() => ToModel(); Model ICached<Model>.ToModel() => ToModel();
TResult ICached<Model>.ToModel<TResult>() => ToModel<TResult>();
void ICached<Model>.Update(Model model) => Update(model); void ICached<Model>.Update(Model model) => Update(model);
#endregion #endregion
} }


+ 14
- 15
src/Discord.Net.WebSocket/Entities/Users/SocketThreadUser.cs View File

@@ -151,14 +151,14 @@ namespace Discord.WebSocket


internal static SocketThreadUser Create(SocketGuild guild, SocketThreadChannel thread, Model model, SocketGuildUser member) internal static SocketThreadUser Create(SocketGuild guild, SocketThreadChannel thread, Model model, SocketGuildUser member)
{ {
var entity = new SocketThreadUser(guild.Discord, guild.Id, thread.Id, model.UserId.Value);
var entity = new SocketThreadUser(guild.Discord, guild.Id, thread.Id, model.Id);
entity.Update(model); entity.Update(model);
return entity; return entity;
} }


internal static SocketThreadUser Create(DiscordSocketClient client, ulong guildId, ulong threadId, Model model) internal static SocketThreadUser Create(DiscordSocketClient client, ulong guildId, ulong threadId, Model model)
{ {
var entity = new SocketThreadUser(client, guildId, threadId, model.UserId.Value);
var entity = new SocketThreadUser(client, guildId, threadId, model.Id);
entity.Update(model); entity.Update(model);
return entity; return entity;
} }
@@ -242,7 +242,12 @@ namespace Discord.WebSocket


public override void Dispose() public override void Dispose()
{ {
if (IsFreed)
return;

GC.SuppressFinalize(this); GC.SuppressFinalize(this);
Discord.StateManager.GetThreadMemberStore(_threadId)?.RemoveReference(Id);
IsFreed = true;
} }




@@ -255,27 +260,21 @@ namespace Discord.WebSocket
#region Cache #region Cache
private class CacheModel : Model private class CacheModel : Model
{ {
public ulong Id { get; set; }
public ulong? ThreadId { get; set; } public ulong? ThreadId { get; set; }
public ulong? UserId { get; set; }
public DateTimeOffset JoinedAt { get; set; } public DateTimeOffset JoinedAt { get; set; }

ulong IEntityModel<ulong>.Id { get => UserId.GetValueOrDefault(); set => throw new NotSupportedException(); }
} }


internal new Model ToModel() => ToModel<CacheModel>();

internal new TModel ToModel<TModel>() where TModel : Model, new()
internal new Model ToModel()
{ {
return new TModel
{
JoinedAt = ThreadJoinedAt,
ThreadId = _threadId,
UserId = Id
};
var model = Discord.StateManager.GetModel<Model, CacheModel>();
model.Id = Id;
model.ThreadId = _threadId;
model.JoinedAt = ThreadJoinedAt;
return model;
} }


Model ICached<Model>.ToModel() => ToModel(); Model ICached<Model>.ToModel() => ToModel();
TResult ICached<Model>.ToModel<TResult>() => ToModel<TResult>();
void ICached<Model>.Update(Model model) => Update(model); void ICached<Model>.Update(Model model) => Update(model);
#endregion #endregion
} }


+ 8
- 17
src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs View File

@@ -137,29 +137,20 @@ namespace Discord.WebSocket
public ulong Id { get; set; } public ulong Id { get; set; }
} }


internal TModel ToModel<TModel>() where TModel : Model, new()
internal Model ToModel()
{ {
return new TModel
{
Avatar = AvatarId,
Discriminator = Discriminator,
Id = Id,
IsBot = IsBot,
Username = Username
};
var model = Discord.StateManager.GetModel<Model, CacheModel>();
model.Avatar = AvatarId;
model.Discriminator = Discriminator;
model.Id = Id;
model.IsBot = IsBot;
model.Username = Username;
return model;
} }


internal Model ToModel()
=> ToModel<CacheModel>();

Model ICached<Model>.ToModel() Model ICached<Model>.ToModel()
=> ToModel(); => ToModel();

TResult ICached<Model>.ToModel<TResult>()
=> ToModel<TResult>();

void ICached<Model>.Update(Model model) => Update(model); void ICached<Model>.Update(Model model) => Update(model);

bool ICached.IsFreed => IsFreed; bool ICached.IsFreed => IsFreed;


#endregion #endregion


Loading…
Cancel
Save