Skip to content

Commit 0af0659

Browse files
LulalabyCopilot
andcommitted
feat(channels): experimental draft - introduce abstract base channel hierarchy and thread channel abstraction for future channel type splitting/refactor
Co-Authored-By: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent 5ef2c25 commit 0af0659

26 files changed

+387
-54
lines changed

DisCatSharp.CommandsNext/CommandsNextExtension.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ internal CommandsNextExtension(CommandsNextConfiguration cfg)
8282
[typeof(DiscordGuild)] = new DiscordGuildConverter(),
8383
[typeof(DiscordMessage)] = new DiscordMessageConverter(),
8484
[typeof(DiscordEmoji)] = new DiscordEmojiConverter(),
85-
[typeof(DiscordThreadChannel)] = new DiscordThreadChannelConverter(),
85+
[typeof(DiscordXThreadChannel)] = new DiscordThreadChannelConverter(),
8686
[typeof(DiscordInvite)] = new DiscordInviteConverter(),
8787
[typeof(DiscordColor)] = new DiscordColorConverter(),
8888
[typeof(DiscordScheduledEvent)] = new DiscordScheduledEventConverter()
@@ -114,7 +114,7 @@ internal CommandsNextExtension(CommandsNextConfiguration cfg)
114114
[typeof(DiscordGuild)] = "guild",
115115
[typeof(DiscordMessage)] = "message",
116116
[typeof(DiscordEmoji)] = "emoji",
117-
[typeof(DiscordThreadChannel)] = "thread",
117+
[typeof(DiscordXThreadChannel)] = "thread",
118118
[typeof(DiscordInvite)] = "invite",
119119
[typeof(DiscordColor)] = "color",
120120
[typeof(DiscordScheduledEvent)] = "event"

DisCatSharp.CommandsNext/Converters/EntityConverters.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,14 @@ async Task<Optional<DiscordChannel>> IArgumentConverter<DiscordChannel>.ConvertA
135135
/// <summary>
136136
/// Represents a discord thread channel converter.
137137
/// </summary>
138-
public class DiscordThreadChannelConverter : IArgumentConverter<DiscordThreadChannel>
138+
public class DiscordThreadChannelConverter : IArgumentConverter<DiscordXThreadChannel>
139139
{
140140
/// <summary>
141141
/// Converts a string.
142142
/// </summary>
143143
/// <param name="value">The string to convert.</param>
144144
/// <param name="ctx">The command context.</param>
145-
async Task<Optional<DiscordThreadChannel>> IArgumentConverter<DiscordThreadChannel>.ConvertAsync(string value, CommandContext ctx)
145+
async Task<Optional<DiscordXThreadChannel>> IArgumentConverter<DiscordXThreadChannel>.ConvertAsync(string value, CommandContext ctx)
146146
{
147147
if (ulong.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var tid))
148148
{

DisCatSharp/Clients/DiscordClient.Dispatch.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ internal async Task HandleDispatchAsync(GatewayPayload payload)
5858
ulong uid;
5959
DiscordStageInstance stg = default;
6060
DiscordIntegration itg = default;
61-
DiscordThreadChannel trd = default;
61+
DiscordXThreadChannel trd = default;
6262
DiscordThreadChannelMember trdm = default;
6363
DiscordScheduledEvent gse = default;
6464
TransportUser usr = default;
@@ -511,23 +511,23 @@ internal async Task HandleDispatchAsync(GatewayPayload payload)
511511
#region Thread
512512

513513
case "thread_create":
514-
trd = DiscordJson.DeserializeObject<DiscordThreadChannel>(payloadString, this);
514+
trd = DiscordJson.DeserializeObject<DiscordXThreadChannel>(payloadString, this);
515515
await this.OnThreadCreateEventAsync(trd).ConfigureAwait(false);
516516
break;
517517

518518
case "thread_update":
519-
trd = DiscordJson.DeserializeObject<DiscordThreadChannel>(payloadString, this);
519+
trd = DiscordJson.DeserializeObject<DiscordXThreadChannel>(payloadString, this);
520520
await this.OnThreadUpdateEventAsync(trd).ConfigureAwait(false);
521521
break;
522522

523523
case "thread_delete":
524-
trd = DiscordJson.DeserializeObject<DiscordThreadChannel>(payloadString, this);
524+
trd = DiscordJson.DeserializeObject<DiscordXThreadChannel>(payloadString, this);
525525
await this.OnThreadDeleteEventAsync(trd).ConfigureAwait(false);
526526
break;
527527

528528
case "thread_list_sync":
529529
gid = (ulong)dat["guild_id"]!;
530-
var trds = DiscordJson.DeserializeIEnumerableObject<IReadOnlyList<DiscordThreadChannel>>(dat["threads"]!.ToString(), this);
530+
var trds = DiscordJson.DeserializeIEnumerableObject<IReadOnlyList<DiscordXThreadChannel>>(dat["threads"]!.ToString(), this);
531531
var trms = DiscordJson.DeserializeIEnumerableObject<IReadOnlyList<DiscordThreadChannelMember>>(dat["members"]!.ToString(), this);
532532
await this.OnThreadListSyncEventAsync(this.GuildsInternal[gid], dat["channel_ids"]!.ToObject<IReadOnlyList<ulong?>>()!, trds, trms).ConfigureAwait(false);
533533
break;
@@ -3258,7 +3258,7 @@ internal async Task OnStageInstanceDeleteEventAsync(DiscordStageInstance stage)
32583258
/// Handles the thread create event.
32593259
/// </summary>
32603260
/// <param name="thread">The created thread.</param>
3261-
internal async Task OnThreadCreateEventAsync(DiscordThreadChannel thread)
3261+
internal async Task OnThreadCreateEventAsync(DiscordXThreadChannel thread)
32623262
{
32633263
thread.Discord = this;
32643264
this.InternalGetCachedGuild(thread.GuildId).ThreadsInternal.AddOrUpdate(thread.Id, thread, (oldThread, newThread) => newThread);
@@ -3275,7 +3275,7 @@ internal async Task OnThreadCreateEventAsync(DiscordThreadChannel thread)
32753275
/// Handles the thread update event.
32763276
/// </summary>
32773277
/// <param name="thread">The updated thread.</param>
3278-
internal async Task OnThreadUpdateEventAsync(DiscordThreadChannel thread)
3278+
internal async Task OnThreadUpdateEventAsync(DiscordXThreadChannel thread)
32793279
{
32803280
if (thread == null)
32813281
return;
@@ -3284,7 +3284,7 @@ internal async Task OnThreadUpdateEventAsync(DiscordThreadChannel thread)
32843284
var guild = thread.Guild;
32853285

32863286
var threadNew = this.InternalGetCachedThread(thread.Id);
3287-
DiscordThreadChannel threadOld = null;
3287+
DiscordXThreadChannel threadOld = null;
32883288
ThreadUpdateEventArgs updateEvent;
32893289

32903290
if (threadNew != null)
@@ -3364,7 +3364,7 @@ internal async Task OnThreadUpdateEventAsync(DiscordThreadChannel thread)
33643364
/// Handles the thread delete event.
33653365
/// </summary>
33663366
/// <param name="thread">The deleted thread.</param>
3367-
internal async Task OnThreadDeleteEventAsync(DiscordThreadChannel thread)
3367+
internal async Task OnThreadDeleteEventAsync(DiscordXThreadChannel thread)
33683368
{
33693369
if (thread == null)
33703370
return;
@@ -3391,7 +3391,7 @@ internal async Task OnThreadDeleteEventAsync(DiscordThreadChannel thread)
33913391
/// <param name="channelIds">The synced channel ids.</param>
33923392
/// <param name="threads">The synced threads.</param>
33933393
/// <param name="members">The synced thread members.</param>
3394-
internal async Task OnThreadListSyncEventAsync(DiscordGuild guild, IReadOnlyList<ulong?> channelIds, IReadOnlyList<DiscordThreadChannel> threads, IReadOnlyList<DiscordThreadChannelMember> members)
3394+
internal async Task OnThreadListSyncEventAsync(DiscordGuild guild, IReadOnlyList<ulong?> channelIds, IReadOnlyList<DiscordXThreadChannel> threads, IReadOnlyList<DiscordThreadChannelMember> members)
33953395
{
33963396
guild.Discord = this;
33973397

DisCatSharp/Clients/DiscordClient.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ public bool TryGetChannel(ulong id, [NotNullWhen(true)] out DiscordChannel? chan
839839
/// <exception cref="NotFoundException">Thrown when the thread does not exist.</exception>
840840
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
841841
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
842-
public async Task<DiscordThreadChannel> GetThreadAsync(ulong id, bool fetch = false)
842+
public async Task<DiscordXThreadChannel> GetThreadAsync(ulong id, bool fetch = false)
843843
=> (fetch ? null : this.InternalGetCachedThread(id)) ?? await this.ApiClient.GetThreadAsync(id).ConfigureAwait(false);
844844

845845
/// <summary>
@@ -849,7 +849,7 @@ public async Task<DiscordThreadChannel> GetThreadAsync(ulong id, bool fetch = fa
849849
/// <param name="thread">The thread, if found.</param>
850850
/// <param name="fetch">Whether to ignore the cache. Defaults to true.</param>
851851
/// <returns>True if found, otherwise false.</returns>
852-
public bool TryGetThread(ulong id, [NotNullWhen(true)] out DiscordThreadChannel? thread, bool fetch = true)
852+
public bool TryGetThread(ulong id, [NotNullWhen(true)] out DiscordXThreadChannel? thread, bool fetch = true)
853853
{
854854
try
855855
{
@@ -1474,7 +1474,7 @@ public Task<IReadOnlyList<DiscordSoundboardSound>> ListDefaultSoundboardSoundsAs
14741474
/// </summary>
14751475
/// <param name="threadId">The target thread id.</param>
14761476
/// <returns>The requested thread.</returns>
1477-
internal DiscordThreadChannel? InternalGetCachedThread(ulong threadId)
1477+
internal DiscordXThreadChannel? InternalGetCachedThread(ulong threadId)
14781478
{
14791479
if (this.GuildsInternal == null || this.GuildsInternal.Count is 0)
14801480
return null;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
3+
using DisCatSharp.Enums;
4+
5+
using Newtonsoft.Json;
6+
7+
namespace DisCatSharp.Entities;
8+
9+
/// <summary>
10+
/// Represents the base class for all Discord channel types.
11+
/// </summary>
12+
public abstract class BaseDiscordChannel : SnowflakeObject, IEquatable<BaseDiscordChannel>
13+
{
14+
15+
/// <summary>
16+
/// Gets the channel type.
17+
/// </summary>
18+
[JsonProperty("type")]
19+
public ChannelType Type { get; internal set; }
20+
21+
/// <summary>
22+
/// Checks whether this <see cref="BaseDiscordChannel" /> is equal to another <see cref="BaseDiscordChannel" />.
23+
/// </summary>
24+
public bool Equals(BaseDiscordChannel other)
25+
=> other is not null && (ReferenceEquals(this, other) || this.Id == other.Id);
26+
27+
public override bool Equals(object obj)
28+
=> this.Equals(obj as BaseDiscordChannel);
29+
30+
public override int GetHashCode()
31+
=> this.Id.GetHashCode();
32+
33+
public static bool operator ==(BaseDiscordChannel e1, BaseDiscordChannel e2)
34+
{
35+
var o1 = e1 as object;
36+
var o2 = e2 as object;
37+
return (o1 != null || o2 == null) && (o1 == null || o2 != null) && ((o1 == null && o2 == null) || e1.Id == e2.Id);
38+
}
39+
40+
public static bool operator !=(BaseDiscordChannel e1, BaseDiscordChannel e2)
41+
=> !(e1 == e2);
42+
}

DisCatSharp/Entities/Channel/DiscordChannel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,7 @@ public async Task<DiscordScheduledEvent> CreateScheduledEventAsync(string name,
12731273
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
12741274
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
12751275
/// <exception cref="NotSupportedException">Thrown when a wrong <paramref name="type" /> was given.</exception>
1276-
public async Task<DiscordThreadChannel> CreateThreadAsync(string name, ThreadAutoArchiveDuration autoArchiveDuration = ThreadAutoArchiveDuration.OneHour, ChannelType type = ChannelType.PublicThread, int? rateLimitPerUser = null, string reason = null) =>
1276+
public async Task<DiscordXThreadChannel> CreateThreadAsync(string name, ThreadAutoArchiveDuration autoArchiveDuration = ThreadAutoArchiveDuration.OneHour, ChannelType type = ChannelType.PublicThread, int? rateLimitPerUser = null, string reason = null) =>
12771277
type != ChannelType.NewsThread && type != ChannelType.PublicThread && type != ChannelType.PrivateThread
12781278
? throw new NotSupportedException("Wrong thread type given.")
12791279
: !this.IsThreadHolder()
@@ -1300,7 +1300,7 @@ public async Task<DiscordThreadChannel> CreateThreadAsync(string name, ThreadAut
13001300
/// <exception cref="NotFoundException">Thrown when the guild hasn't enabled threads atm.</exception>
13011301
/// <exception cref="BadRequestException">Thrown when an invalid parameter was provided.</exception>
13021302
/// <exception cref="ServerErrorException">Thrown when Discord is unable to process the request.</exception>
1303-
public async Task<DiscordThreadChannel> CreatePostAsync(string name, DiscordMessageBuilder builder, int? rateLimitPerUser = null, IEnumerable<ForumPostTag>? tags = null, string reason = null)
1303+
public async Task<DiscordXThreadChannel> CreatePostAsync(string name, DiscordMessageBuilder builder, int? rateLimitPerUser = null, IEnumerable<ForumPostTag>? tags = null, string reason = null)
13041304
=> this.Type != ChannelType.Forum ? throw new NotSupportedException("Parent channel must be forum.") : await this.Discord.ApiClient.CreateThreadAsync(this.Id, null, name, null, null, rateLimitPerUser, tags, builder, true, reason).ConfigureAwait(false);
13051305

13061306
/// <summary>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*using System;
2+
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Linq;
4+
using DisCatSharp.Enums;
5+
6+
namespace DisCatSharp.Entities
7+
{
8+
/// <summary>
9+
/// Polymorphic converter for Discord channel types.
10+
/// </summary>
11+
public class DiscordChannelConverter : JsonConverter<BaseDiscordChannel>
12+
{
13+
public override BaseDiscordChannel ReadJson(JsonReader reader, Type objectType, BaseDiscordChannel existingValue, bool hasExistingValue, JsonSerializer serializer)
14+
{
15+
var jo = JObject.Load(reader);
16+
var type = (ChannelType)jo["type"].Value<int>();
17+
BaseDiscordChannel channel;
18+
switch (type)
19+
{
20+
case ChannelType.Private:
21+
channel = new DiscordDmChannel();
22+
break;
23+
case ChannelType.Group:
24+
channel = new DiscordGroupDmChannel();
25+
break;
26+
case ChannelType.Text:
27+
channel = new DiscordTextChannel();
28+
break;
29+
case ChannelType.News:
30+
channel = new DiscordAnnouncementChannel();
31+
break;
32+
case ChannelType.Forum:
33+
channel = new DiscordForumChannel();
34+
break;
35+
case ChannelType.Media:
36+
channel = new DiscordMediaChannel();
37+
break;
38+
case ChannelType.PublicThread:
39+
case ChannelType.PrivateThread:
40+
case ChannelType.NewsThread:
41+
channel = new DiscordThreadChannel();
42+
break;
43+
case ChannelType.Voice:
44+
channel = new DiscordVoiceChannel();
45+
break;
46+
case ChannelType.Stage:
47+
channel = new DiscordStageChannel();
48+
break;
49+
case ChannelType.Category:
50+
channel = new DiscordCategoryChannel();
51+
break;
52+
default:
53+
channel = new DiscordChannel(); // fallback
54+
break;
55+
}
56+
serializer.Populate(jo.CreateReader(), channel);
57+
return channel;
58+
}
59+
60+
public override void WriteJson(JsonWriter writer, BaseDiscordChannel value, JsonSerializer serializer)
61+
{
62+
serializer.Serialize(writer, value);
63+
}
64+
}
65+
}
66+
*/
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using Newtonsoft.Json;
2+
3+
namespace DisCatSharp.Entities;
4+
5+
/// <summary>
6+
/// Represents a base class for all guild channels.
7+
/// </summary>
8+
public abstract class DiscordGuildChannel : BaseDiscordChannel
9+
{
10+
/// <summary>
11+
/// Gets the guild id this channel belongs to.
12+
/// </summary>
13+
[JsonProperty("guild_id", NullValueHandling = NullValueHandling.Ignore)]
14+
public ulong? GuildId { get; internal set; }
15+
16+
/// <summary>
17+
/// Gets the channel name.
18+
/// </summary>
19+
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
20+
public string Name { get; internal set; }
21+
22+
/// <summary>
23+
/// Gets the channel position.
24+
/// </summary>
25+
[JsonProperty("position", NullValueHandling = NullValueHandling.Ignore)]
26+
public int? Position { get; internal set; }
27+
28+
/// <summary>
29+
/// Gets the permission overwrites for this channel.
30+
/// </summary>
31+
[JsonProperty("permission_overwrites", NullValueHandling = NullValueHandling.Ignore)]
32+
public object[] PermissionOverwrites { get; internal set; } // Replace object with actual type
33+
34+
/// <summary>
35+
/// Gets the parent category id.
36+
/// </summary>
37+
[JsonProperty("parent_id", NullValueHandling = NullValueHandling.Ignore)]
38+
public ulong? ParentId { get; internal set; }
39+
40+
/// <summary>
41+
/// Gets the channel flags.
42+
/// </summary>
43+
[JsonProperty("flags", NullValueHandling = NullValueHandling.Ignore)]
44+
public int? Flags { get; internal set; }
45+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Newtonsoft.Json;
2+
3+
namespace DisCatSharp.Entities;
4+
5+
/// <summary>
6+
/// Represents a base class for all guild text-based channels.
7+
/// </summary>
8+
public abstract class DiscordGuildTextChannel : DiscordGuildChannel
9+
{
10+
/// <summary>
11+
/// Gets the channel topic.
12+
/// </summary>
13+
[JsonProperty("topic", NullValueHandling = NullValueHandling.Ignore)]
14+
public string Topic { get; internal set; }
15+
16+
/// <summary>
17+
/// Gets the last message id in the channel.
18+
/// </summary>
19+
[JsonProperty("last_message_id", NullValueHandling = NullValueHandling.Ignore)]
20+
public ulong? LastMessageId { get; internal set; }
21+
22+
/// <summary>
23+
/// Gets the rate limit per user (slowmode).
24+
/// </summary>
25+
[JsonProperty("rate_limit_per_user", NullValueHandling = NullValueHandling.Ignore)]
26+
public int? RateLimitPerUser { get; internal set; }
27+
28+
/// <summary>
29+
/// Gets the nsfw status.
30+
/// </summary>
31+
[JsonProperty("nsfw", NullValueHandling = NullValueHandling.Ignore)]
32+
public bool? IsNsfw { get; internal set; }
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Newtonsoft.Json;
2+
3+
namespace DisCatSharp.Entities;
4+
5+
/// <summary>
6+
/// Represents a base class for all guild voice-based channels.
7+
/// </summary>
8+
public abstract class DiscordGuildVoiceChannel : DiscordGuildChannel
9+
{
10+
/// <summary>
11+
/// Gets the bitrate (in bits) of the voice channel.
12+
/// </summary>
13+
[JsonProperty("bitrate", NullValueHandling = NullValueHandling.Ignore)]
14+
public int? Bitrate { get; internal set; }
15+
16+
/// <summary>
17+
/// Gets the user limit of the voice channel.
18+
/// </summary>
19+
[JsonProperty("user_limit", NullValueHandling = NullValueHandling.Ignore)]
20+
public int? UserLimit { get; internal set; }
21+
22+
/// <summary>
23+
/// Gets the voice region id (deprecated, but present in API).
24+
/// </summary>
25+
[JsonProperty("rtc_region", NullValueHandling = NullValueHandling.Ignore)]
26+
public string RtcRegion { get; internal set; }
27+
28+
/// <summary>
29+
/// Gets the video quality mode.
30+
/// </summary>
31+
[JsonProperty("video_quality_mode", NullValueHandling = NullValueHandling.Ignore)]
32+
public int? VideoQualityMode { get; internal set; }
33+
}

0 commit comments

Comments
 (0)