This commit is contained in:
Kecskeméti László 2024-07-28 19:40:54 +02:00
parent da80a3133d
commit 265647ca7c
13 changed files with 206 additions and 103 deletions

View File

@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
namespace Discord.API;
public class ChannelData
public class ChannelData : IId
{
public required ulong Id { get; init; }
public required int Type { get; init; }

View File

@ -0,0 +1,6 @@
namespace Discord.API;
public interface IId
{
public ulong Id {get;}
}

View File

@ -2,7 +2,7 @@ using System.Text.Json.Serialization;
namespace Discord.API;
public class RoleData : IJsonOnDeserialized
public class RoleData : IJsonOnDeserialized, IId
{
public required ulong Id { get; init; }
public required string Name { get; init; }

View File

@ -0,0 +1,20 @@
namespace Discord.Model;
public abstract class BaseType<T>
{
public virtual Snowflake Id {get; }
public event EventHandler? Deleted;
public event EventHandler? Updated;
protected BaseType(Snowflake id){
this.Id=id;
}
protected BaseType(){
}
internal virtual void Delete(){
Deleted?.Invoke(this, EventArgs.Empty);
}
internal abstract void Update(T data);
}

View File

@ -1,38 +0,0 @@
using Discord.API;
namespace Discord.Model;
public class Channel
{
public enum ChannelType {
GuildText = 0,
DM = 1,
GuildVoice = 2,
GroupDM = 3,
GuildCategory = 4,
GuildAnnouncement = 5,
AnnouncementThread = 10,
PublicThread = 11,
PrivateThread = 12,
GuildStageVoice = 13,
GuildDirectory = 14,
GuildForum = 15,
GuildMedia = 16
}
public Snowflake Id { get; }
public ChannelType Type { get; protected set; }
public Channel(ChannelData data){
Id = data.Id;
Update(data, false);
}
protected void Update(ChannelData data, bool call_base_update){
Type = (ChannelType)data.Type;
}
public virtual void Update(ChannelData data){
Update(data, true);
}
}

View File

@ -0,0 +1,18 @@
namespace Discord.Model;
public enum ChannelType
{
GuildText = 0,
DM = 1,
GuildVoice = 2,
GroupDM = 3,
GuildCategory = 4,
GuildAnnouncement = 5,
AnnouncementThread = 10,
PublicThread = 11,
PrivateThread = 12,
GuildStageVoice = 13,
GuildDirectory = 14,
GuildForum = 15,
GuildMedia = 16
}

View File

@ -0,0 +1,71 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using Discord.API;
using Serilog;
namespace Discord.Model;
public abstract class DiscordCollection<D, T> : IReadOnlyDictionary<Snowflake, T> where T : BaseType<D> where D: IId
{
internal DiscordCollection(int capacity){
_dict = new(capacity);
}
internal void Update(D[] data){
// Update existing, add new items
foreach(var item in data){
if(_dict.TryGetValue(item.Id, out T? obj)){
obj.Update(item);
}else{
_dict.Add(item.Id, CreateInstance(item));
}
}
// Delete items no longer present
foreach(Snowflake id in _dict.Select(item => item.Value.Id)){
if(!data.Any(data => data.Id == id)){
T obj = _dict[id];
_dict.Remove(id);
obj.Delete();
}
}
}
internal void Remove(Snowflake id){
if(_dict.TryGetValue(id, out T? item)){
_dict.Remove(id);
item.Delete();
}else{
Log.Warning("Trying to delete item not in the dictionary. Id: {id}, Type: {type}", id, typeof(T));
}
}
internal void UpdateSingle(D data){
if(_dict.TryGetValue(data.Id, out T? obj)){
obj.Update(data);
}else{
_dict.Add(data.Id, CreateInstance(data));
}
}
protected abstract T CreateInstance(D data);
private Dictionary<Snowflake, T> _dict;
public T this[Snowflake key] => _dict[key];
public IEnumerable<Snowflake> Keys => _dict.Keys;
public IEnumerable<T> Values => _dict.Values;
public int Count => _dict.Count;
public bool ContainsKey(Snowflake key) => _dict.ContainsKey(key);
public IEnumerator<KeyValuePair<Snowflake, T>> GetEnumerator() => _dict.GetEnumerator();
public bool TryGetValue(Snowflake key, [MaybeNullWhen(false)] out T value)
=> _dict.TryGetValue(key, out value);
IEnumerator IEnumerable.GetEnumerator() => _dict.GetEnumerator();
}

View File

@ -0,0 +1,34 @@
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using Discord.API;
namespace Discord.Model;
public class Guild : BaseType<GuildData>
{
public string Name { get; private set; }
public ulong? AfkChannelId { get; private set; }
public int AfkTimeout { get; private set; }
public RoleCollection Roles {get; }
public ulong? SystemChannelId { get; private set; }
public uint SystemChannelFlags { get; private set; }
public string? Description { get; private set; }
public int NsfwLevel { get; private set; }
internal Guild(GuildData data) : base(data.Id){
Roles = new(data.Roles.Length);
Update(data);
}
[MemberNotNull(nameof(Name))]
internal override void Update(GuildData data){
Name = data.Name;
AfkChannelId = data.AfkChannelId;
AfkTimeout = data.AfkTimeout;
Roles.Update(data.Roles);
SystemChannelId = data.SystemChannelId;
SystemChannelFlags = data.SystemChannelFlags;
Description = data.Description;
NsfwLevel = data.NsfwLevel;
}
}

View File

@ -4,44 +4,37 @@ using Serilog;
namespace Discord.Model;
public class GuildChannel : Channel
public class GuildChannel : BaseType<GuildChannelData>
{
public string Name {get; protected set;}
public Snowflake? ParentId {get; protected set;}
public string Name {get; private set;}
public Snowflake? ParentId {get; private set;}
public ChannelType Type {get; private set;}
internal GuildChannel(GuildChannelData data) : base(data){
Update(data, false);
//TODO: Optimise this shit
protected virtual ChannelType[] ValidTypes { get; } = [
ChannelType.GuildText,
ChannelType.GuildVoice,
ChannelType.GuildCategory,
ChannelType.GuildAnnouncement,
ChannelType.GuildStageVoice,
ChannelType.GuildForum,
ChannelType.GuildMedia
];
internal GuildChannel(GuildChannelData data) : base(data.Id) {
Update(data);
}
[MemberNotNull(nameof(Name))]
protected void Update(GuildChannelData data, bool call_base_update)
internal override void Update(GuildChannelData data)
{
if((ChannelType)data.Type is not ChannelType.GuildText or
ChannelType.GuildVoice or
ChannelType.GuildCategory or
ChannelType.GuildAnnouncement or
ChannelType.AnnouncementThread or
ChannelType.PublicThread or
ChannelType.PrivateThread or
ChannelType.GuildStageVoice or
ChannelType.GuildForum or
ChannelType.GuildMedia)
if(!ValidTypes.Contains((ChannelType)data.Type))
{
Log.Warning("GuildChannel has type {type} that is not compatible", (ChannelType)data.Type);
}
Name = data.Name;
ParentId = data.ParentId;
if(call_base_update) base.Update(data);
}
public override void Update(ChannelData data)
{
if(data is GuildChannelData guild_data){
Update(guild_data, true);
}else{
throw new ArgumentException("data must be GuildChannelData", nameof(data));
}
Type = (ChannelType) data.Type;
}
}

View File

@ -5,25 +5,12 @@ namespace Discord.Model;
public class GuildTextChannel : GuildChannel
{
protected override ChannelType[] ValidTypes { get; } = [
ChannelType.GuildText,
ChannelType.GuildAnnouncement,
ChannelType.GuildForum
];
internal GuildTextChannel(GuildChannelData data) : base(data){
Update(data, false);
}
protected new void Update(GuildChannelData data, bool call_base_update){
if((ChannelType)data.Type is not ChannelType.GuildText or ChannelType.GuildAnnouncement){
Log.Warning("Channel type is not compatible with GuildTextChannel: {type}", (ChannelType)data.Type);
}
if(call_base_update) base.Update(data, call_base_update);
}
public override void Update(ChannelData data)
{
if(data is GuildChannelData guild_data){
Update(guild_data, true);
}else{
throw new ArgumentException("data must be GuildChannelData", nameof(data));
}
}
}

View File

@ -1,5 +1,5 @@
using System.Data;
using Discord.API;
using Discord.API;
using Serilog;
namespace Discord.Model;
@ -7,22 +7,23 @@ public class GuildVoiceChannel : GuildChannel
{
public int Bitrate {get; protected set;}
protected override ChannelType[] ValidTypes {get; } = [
ChannelType.GuildVoice,
ChannelType.GuildStageVoice,
ChannelType.GuildMedia
];
internal GuildVoiceChannel(GuildChannelData data) : base(data)
{
Update(data, false);
}
protected new void Update(GuildChannelData data, bool call_base_update){
Bitrate = data.Bitrate!.Value;
if(call_base_update) base.Update(data, call_base_update);
}
public override void Update(ChannelData data)
internal override void Update(GuildChannelData data)
{
if(data is GuildChannelData guild_data){
Update(guild_data, true);
if(data.Bitrate != null){
Bitrate = data.Bitrate.Value;
}else{
throw new ArgumentException("data must be GuildChannelData", nameof(data));
Log.Warning("VoiceChannel data did not contain Bitrate");
}
base.Update(data);
}
}

View File

@ -3,9 +3,8 @@ using Discord.API;
namespace Discord.Model;
public sealed class Role
public sealed class Role : BaseType<RoleData>
{
public Snowflake Id { get; private set; }
public string Name { get; private set; }
public uint Color { get; private set; }
public bool Hoist { get; private set; }
@ -13,13 +12,12 @@ public sealed class Role
public bool Managed { get; private set; }
public bool Mentionable { get; private set; }
public Role(RoleData data){
this.Id = data.Id;
public Role(RoleData data) : base(data.Id){
Update(data);
}
[MemberNotNull(nameof(Name))]
private void Update(RoleData data){
internal override void Update(RoleData data){
this.Name = data.Name;
this.Color = data.Color;
this.Hoist = data.Hoist;

View File

@ -0,0 +1,13 @@
using Discord.API;
namespace Discord.Model;
public class RoleCollection : DiscordCollection<RoleData, Role>
{
public RoleCollection(int capacity) : base(capacity)
{
}
protected override Role CreateInstance(RoleData data)
=> new Role(data);
}