Update CS models

This commit is contained in:
Rory&
2026-05-08 22:20:41 +02:00
parent 7e152be9dd
commit a39a443196
13 changed files with 690 additions and 2 deletions
@@ -0,0 +1,79 @@
using System.Text.Json.Serialization;
namespace Spacebar.Models.Api;
public class LoginRequest {
[JsonPropertyName("login")]
public required string Login { get; set; }
[JsonPropertyName("password")]
public required string Password { get; set; }
/// <summary>
/// Whether to un-delete a self-disabled or self-deleted account
/// </summary>
[JsonPropertyName("undelete")]
public bool? Undelete { get; set; }
/// <summary>
/// One of gift, guild_template, guild_invite, dm_invite, friend_invite, role_subscription or role_subscription_setting
/// </summary>
[JsonPropertyName("login_source")]
public string? LoginSource { get; set; }
[JsonPropertyName("gift_code_sku_id")]
public string? GiftCodeSkuId { get; set; }
}
/// <summary>
/// Note: nullable fields missing "if the login was not completed"
/// </summary>
public class LoginResponse {
[JsonPropertyName("user_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public ulong UserId { get; set; }
[JsonPropertyName("token")]
public string? Token { get; set; }
[JsonPropertyName("user_settings")]
public LoginUserSettings? UserSettings { get; set; }
/// <summary>
/// Values: update_password
/// </summary>
[JsonPropertyName("required_actions")]
public List<string>? RequiredActions { get; set; }
/// <summary>
/// MFA ticket
/// </summary>
[JsonPropertyName("ticket")]
public string? Ticket { get; set; }
[JsonPropertyName("login_instance_id")]
public string? LoginInstanceId { get; set; }
[JsonPropertyName("mfa")]
public bool? Mfa { get; set; }
[JsonPropertyName("totp")]
public bool? Totp { get; set; }
[JsonPropertyName("sms")]
public bool? Sms { get; set; }
[JsonPropertyName("backup")]
public bool? Backup { get; set; }
[JsonPropertyName("webauthn")]
public string? Webauthn { get; set; }
public class LoginUserSettings {
[JsonPropertyName("locale")]
public string Locale { get; set; }
[JsonPropertyName("theme")]
public string Theme { get; set; }
}
}
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
@@ -0,0 +1,29 @@
using System.Text.Json.Nodes;
namespace Spacebar.Models.Api;
public class SpacebarApiException : Exception {
public int Code { get; set; }
public string? Request { get; set; } // Spacebar extension
// public Dictionary<string, FieldErrorList> Errors { get; set; }
public JsonObject? Errors { get; set; }
public class FieldErrorList {
// public
}
public SpacebarApiException(string? message) : base(message) {
}
// TODO: abstract out to HTTP layer
public static SpacebarApiException FromJson(JsonObject resp) {
var ex = new SpacebarApiException(resp["message"]!.GetValue<string>()) {
Code = resp["code"]!.GetValue<int>(),
Request = resp["request"]?.GetValue<string>(),
Errors = resp["errors"]?.AsObject()
};
return ex;
}
}
@@ -0,0 +1,83 @@
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace Spacebar.Models.Gateway;
public class GatewayPayload {
[JsonPropertyName("op")]
public GatewayOpcode Opcode { get; set; }
[JsonPropertyName("d")]
public JsonObject? EventData { get; set; }
[JsonPropertyName("s")]
public int? Sequence { get; set; }
[JsonPropertyName("t")]
public string? DispatchEventType { get; set; }
public T? GetData<T>() where T : class {
if (EventData is null) return null;
var sw = Stopwatch.StartNew();
var jso = new JsonSerializerOptions();
if (typeof(T) == typeof(ReadyResponse)) {
Console.WriteLine("Adding ReadyResponse sourcegen");
jso.TypeInfoResolver = new ReadyResponseSerializerContext();
}
else
Console.WriteLine($"No TypeInfoResolver for {typeof(T).FullName}");
var deserialized = EventData.Deserialize<T>(jso);
Console.WriteLine($"Deserialized {typeof(T).FullName} in {sw.Elapsed}");
return deserialized;
}
}
public enum GatewayOpcode {
S2CDispatch,
Heartbeat,
C2SIdentify,
C2SPresenceUpdate,
C2SVoiceStateUpdate,
C2SVoiceServerPing,
C2SResume,
S2CReconnect,
C2SRequestGuildMembers,
S2CInvalidSession,
S2CHello,
S2CHeartbeatAck,
C2SGuildSync,
C2SCallConnect,
C2SGuildSubscriptions,
C2SLobbyConnect,
C2SLobbyDisconnect,
C2SLobbyVoiceStates,
C2SStreamCreate,
C2SStreamDelete,
C2SStreamWatch,
C2SStreamPing,
C2SStreamSetPaused,
C2SLfgSubscription,
C2SRequestGuildApplicationCommands,
C2SEmbeddedActivityCreate,
C2SEmbeddedActivityDelete,
C2SEmbeddedActivityUpdate,
C2SRequestForumUnreads,
C2SRemoteCommand,
C2SRequestDeletedEntityIds,
C2SRequestSoundboardSounds,
C2SSpeedTestCreate,
C2SSpeedTestDelete,
C2SRequestLastMessages,
C2SSearchRecentMembers,
C2SRequestChannelStatuses,
C2SGuildSubscriptionsBulk,
C2SGuildChannelsResync,
C2SRequestChannelMemberCount,
C2SQoSHeartbeat,
C2SUpdateTimeSpentSessionId,
C2SLobbyVoiceServerPing,
C2SRequestChannelInfo
}
@@ -3,6 +3,11 @@ using System.Text.Json.Serialization;
namespace Spacebar.Models.Gateway;
public class HelloResponse {
[JsonPropertyName("heartbeat_interval")]
public int HeartbeatInterval { get; set; }
}
public class IdentifyRequest {
[JsonPropertyName("token")]
public string Token { get; set; }
@@ -32,6 +37,171 @@ public class IdentifyRequest {
public JsonObject? ClientState { get; set; }
}
/// <summary>
/// This class defines all client properties used by discord
/// This should *not* be used as a schema, as the types are merely conventions, and the structure isn't well-defined.
/// </summary>
public class IdentifyClientProperties {
[JsonPropertyName("os")]
public string? OperatingSystem { get; set; }
[JsonPropertyName("os_version")]
public string? OperatingSystemVersion { get; set; }
[JsonPropertyName("os_sdk_version")]
public string? OperatingSystemSdkVersion { get; set; }
[JsonPropertyName("os_arch")]
public string? OperatingSystemArchitecture { get; set; }
[JsonPropertyName("app_arch")]
public string? ApplicationArchitecture { get; set; }
[JsonPropertyName("browser")]
public string? Browser { get; set; }
[JsonPropertyName("browser_user_agent")]
public string? BrowserUserAgent { get; set; }
[JsonPropertyName("browser_version")]
public string? BrowserVersion { get; set; }
[JsonPropertyName("client_build_number")]
public int? ClientBuildNumber { get; set; }
[JsonPropertyName("native_build_number")]
public int? NativeBuildNumber { get; set; }
[JsonPropertyName("client_version")]
public string? ClientVersion { get; set; }
[JsonPropertyName("client_event_source")]
public string? ClientEventSource { get; set; }
[JsonPropertyName("client_app_state")]
public string? ClientAppState { get; set; }
[JsonPropertyName("client_launch_id")]
public string? ClientLaunchId { get; set; }
[JsonPropertyName("client_heartbeat_session_id")]
public string? ClientHeartbeatSessionId { get; set; }
[JsonPropertyName("client_performance_cpu")]
public int? ClientPerformanceCpu { get; set; }
[JsonPropertyName("client_performance_memory")]
public int? ClientPerformanceMemory { get; set; }
[JsonPropertyName("cpu_core_count")]
public int? CpuCoreCount { get; set; }
[JsonPropertyName("release_channel")]
public string? ReleaseChannel { get; set; }
[JsonPropertyName("system_locale")]
public string? SystemLocale { get; set; }
[JsonPropertyName("device")]
public string? DeviceModel { get; set; }
[JsonPropertyName("device_vendor_id")]
public string? DeviceVendorId { get; set; }
[JsonPropertyName("device_advertiser_id")]
public string? DeviceAdvertiserId { get; set; }
[JsonPropertyName("design_id")]
public int? DesignId { get; set; }
[JsonPropertyName("accessibility_support_enabled")]
public string? AccessibilitySupportEnabled { get; set; }
[JsonPropertyName("accessibility_features")]
public int? AccessibilityFeatures { get; set; }
[JsonPropertyName("window_manager")]
public string? WindowManager { get; set; }
[JsonPropertyName("distro")]
public string? Distro { get; set; }
[JsonPropertyName("runtime_environment")]
public string? RuntimeEnvironment { get; set; }
[JsonPropertyName("display_server")]
public string? DisplayServer { get; set; }
[JsonPropertyName("referrer")]
public string? Referrer { get; set; }
[JsonPropertyName("referrer_current")]
public string? ReferrerCurrent { get; set; }
[JsonPropertyName("referring_domain")]
public string? ReferringDomain { get; set; }
[JsonPropertyName("referring_domain_current")]
public string? ReferringDomainCurrent { get; set; }
[JsonPropertyName("search_engine")]
public string? SearchEngine { get; set; }
[JsonPropertyName("search_engine_current")]
public string? SearchEngineCurrent { get; set; }
[JsonPropertyName("mp_keyword")]
public string? MpKeyword { get; set; }
[JsonPropertyName("mp_keyword_current")]
public string? MpKeywordCurrent { get; set; }
[JsonPropertyName("utm_campaign")]
public string? UtmCampaign { get; set; }
[JsonPropertyName("utm_campaign_current")]
public string? UtmCampaignCurrent { get; set; }
[JsonPropertyName("utm_content")]
public string? UtmContent { get; set; }
[JsonPropertyName("utm_content_current")]
public string? UtmContentCurrent { get; set; }
[JsonPropertyName("utm_medium")]
public string? UtmMedium { get; set; }
[JsonPropertyName("utm_medium_current")]
public string? UtmMediumCurrent { get; set; }
[JsonPropertyName("utm_source")]
public string? UtmSource { get; set; }
[JsonPropertyName("utm_source_current")]
public string? UtmSourceCurrent { get; set; }
[JsonPropertyName("utm_term")]
public string? UtmTerm { get; set; }
[JsonPropertyName("utm_term_current")]
public string? UtmTermCurrent { get; set; }
[JsonPropertyName("has_client_mods")]
public bool? HasClientMods { get; set; }
[JsonPropertyName("launch_signature")]
public string? LaunchSignature { get; set; }
[JsonPropertyName("installation_id")]
public string? InstallationId { get; set; }
[JsonPropertyName("is_fast_connect")]
public bool? IsFastConnect { get; set; }
[JsonPropertyName("version")]
public string? Version { get; set; }
}
[Flags]
public enum GatewayIntentFlags : ulong {
Guilds = 1,
@@ -2,6 +2,16 @@ using System.Text.Json.Serialization;
namespace Spacebar.Models.Gateway;
public class HeartbeatRequest {
[JsonPropertyName("seq")]
public required int? Sequence { get; set; }
}
public class QoSHeartbeatRequest : HeartbeatRequest {
[JsonPropertyName("qos")]
public required QoSPayload QoSPayload { get; set; }
}
public class QoSPayload {
[JsonPropertyName("ver")]
public int Version { get; set; }
@@ -1,3 +1,37 @@
using System.Text.Json.Serialization;
using Spacebar.Models.Generic;
namespace Spacebar.Models.Gateway;
public class ReadyResponse { }
public class ReadyResponse {
/* TODO: _trace, analytics_token, api_code_version, auth_session_id_hash, connected_accounts, consents, country_code, experiments, friend_suggestion_count, game_relationships,
geo_ordered_rtc_regions, guild_experiments, guild_join_requests*/
[JsonPropertyName("guilds")]
public required List<Guild> Guilds { get; set; }
[JsonPropertyName("merged_members")]
public List<List<Member>> MergedMembers { get; set; }
// TODO: notification_settings
[JsonPropertyName("presences")]
public List<Presence> Presences { get; set; } // TODO: right type?
[JsonPropertyName("private_channels")]
public List<Channel> PrivateChannels { get; set; }
[JsonPropertyName("read_state")]
public object ReadStates { get; set; } // TODO: schemas
[JsonPropertyName("relationships")]
public List<object> Relationships { get; set; } // TODO: schemas
[JsonPropertyName("resume_gateway_url")]
public string ResumeGatewayUrl { get; set; }
}
[JsonSourceGenerationOptions()]
[JsonSerializable(typeof(ReadyResponse))]
public partial class ReadyResponseSerializerContext : JsonSerializerContext
{
}
@@ -2,6 +2,10 @@ using System.Text.Json.Serialization;
namespace Spacebar.Models.Generic;
public class Channel {
}
public class ChannelPermissionOverwrite {
[JsonPropertyName("id")]
public string Id { get; set; }
@@ -0,0 +1,35 @@
using System.Text.Json.Serialization;
namespace Spacebar.Models.Generic;
public class Emoji {
[JsonPropertyName("id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long Id { get; set; }
[JsonPropertyName("animated")]
public bool Animated { get; set; }
[JsonPropertyName("available")]
public bool Available { get; set; }
[JsonPropertyName("groups")]
public object? Groups { get; set; } // TODO: what is this?
[JsonPropertyName("guild_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long GuildId { get; set; }
[JsonPropertyName("managed")]
public bool Managed { get; set; }
[JsonPropertyName("name")]
public required string Name { get; set; }
[JsonPropertyName("require_colons")]
public bool RequireColons { get; set; }
[JsonPropertyName("roles")]
public List<object?> Roles { get; set; } // TODO: what type was this again?
[JsonPropertyName("user_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long UserId { get; set; }
}
@@ -0,0 +1,133 @@
using System.Diagnostics;
using System.Text.Json.Serialization;
namespace Spacebar.Models.Generic;
[DebuggerDisplay("{Id} ({Name})")]
public class Guild {
[JsonPropertyName("id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long Id { get; set; }
[JsonPropertyName("afk_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long? AfkChannelId { get; set; }
[JsonPropertyName("afk_timeout")]
public int AfkTimeout { get; set; }
[JsonPropertyName("banner")]
public string? Banner { get; set; }
[JsonPropertyName("channels")]
public List<Channel> Channels { get; set; }
[JsonPropertyName("default_message_notifications")]
public int DefaultMessageNotifications { get; set; } // TODO enum
[JsonPropertyName("description")]
public string? Description { get; set; }
[JsonPropertyName("discovery_splash")]
public string? DiscoverySplash { get; set; }
[JsonPropertyName("emojis")]
public List<Emoji> Emojis { get; set; }
[JsonPropertyName("explicit_content_filter")]
public int ExplicitContentFilter { get; set; }
[JsonPropertyName("features")]
public List<string> Features { get; set; }
[JsonPropertyName("guild_scheduled_events")]
public List<object> GuildScheduledEvents { get; set; } // TODO: implement
[JsonPropertyName("icon")]
public string? Icon { get; set; }
[JsonPropertyName("joined_at")]
public DateTimeOffset JoinedAt { get; set; }
[JsonPropertyName("large")]
public bool Large { get; set; }
[JsonPropertyName("max_members")]
public int MaxMembers { get; set; }
[JsonPropertyName("max_presences")]
public int MaxPresences { get; set; }
[JsonPropertyName("max_video_channel_users")]
public int MaxVideoChannelUsers { get; set; }
[JsonPropertyName("member_count")]
public int MemberCount { get; set; }
[JsonPropertyName("mfa_level")]
public int MfaLevel { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("nsfw_level")]
public int NsfwLevel { get; set; }
[JsonPropertyName("owner_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long OwnerId { get; set; }
[JsonPropertyName("preferred_locale")]
public string PreferredLocale { get; set; }
[JsonPropertyName("premium_progress_bar_enabled")]
public bool? PremiumProgressBarEnabled { get; set; }
[JsonPropertyName("premium_subscription_count")]
public int PremiumSubscriptionCount { get; set; }
[JsonPropertyName("premium_tier")]
public int PremiumTier { get; set; }
[JsonPropertyName("presences")]
public List<Presence> Presences { get; set; } // TODO: correct type?
[JsonPropertyName("public_updates_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public long? PublicUpdatesChannelId { get; set; }
[JsonPropertyName("region")]
public string Region { get; set; }
[JsonPropertyName("roles")]
public List<Role> Roles { get; set; }
[JsonPropertyName("rules_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public long? RulesChannelId { get; set; }
[JsonPropertyName("splash")]
public string? Splash { get; set; }
[JsonPropertyName("stickers")]
public List<Sticker> Stickers { get; set; }
[JsonPropertyName("system_channel_flags")]
public int SystemChannelFlags { get; set; } //TODO enum
[JsonPropertyName("system_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public long? SystemChannelId { get; set; }
[JsonPropertyName("threads")]
public List<Channel> Threads { get; set; }
[JsonPropertyName("verification_level")]
public int VerificationLevel { get; set; }
[JsonPropertyName("voice_states")]
public List<object> VoiceStates { get; set; } // TODO: models
[JsonPropertyName("welcome_screen")]
public object WelcomeScreen { get; set; } // TODO: models
[JsonPropertyName("widget_channel_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public long? WidgetChannelId { get; set; }
[JsonPropertyName("widget_enabled")]
public bool WidgetEnabled { get; set; }
}
@@ -0,0 +1,62 @@
using System.Text.Json.Serialization;
using Spacebar.Models.Generic.Constants;
namespace Spacebar.Models.Generic;
public class Role {
[JsonPropertyName("id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long Id { get; set; }
[JsonPropertyName("color"), Obsolete("See Colors instead")]
public int Color { get; set; }
[JsonPropertyName("colors")]
public RoleColors Colors { get; set; }
[JsonPropertyName("flags")]
public int Flags { get; set; }
[JsonPropertyName("guild_id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long GuildId { get; set; }
[JsonPropertyName("hoist")]
public bool Hoist { get; set; }
[JsonPropertyName("icon")]
public string Icon { get; set; }
[JsonPropertyName("managed")]
public bool Managed { get; set; }
[JsonPropertyName("mentionable")]
public bool Mentionable { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("permissions"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required ulong RawPermissions { get; set; }
[JsonIgnore]
public Permissions Permissions {
get => (Permissions)RawPermissions;
set => RawPermissions = (ulong)value;
}
[JsonPropertyName("position")]
public int Position { get; set; }
[JsonPropertyName("unicode_emoji")]
public string UnicodeEmoji { get; set; }
public class RoleColors {
[JsonPropertyName("primary_color")]
public required int PrimaryColor { get; set; }
[JsonPropertyName("secondary_color")]
public int? SecondaryColor { get; set; }
[JsonPropertyName("tertiary_color")]
public int? TertiaryColor { get; set; }
}
}
@@ -0,0 +1,38 @@
using System.Text.Json.Serialization;
namespace Spacebar.Models.Generic;
public class Sticker {
[JsonPropertyName("id"), JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public required long Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("description")]
public string Description { get; set; }
[JsonPropertyName("tags")]
public string Tags { get; set; }
[JsonPropertyName("available")]
public bool Available { get; set; }
[JsonPropertyName("type")]
public StickerType Type { get; set; }
[JsonPropertyName("format_type")]
public StickerFormatType FormatType { get; set; }
}
public enum StickerType {
Standard = 1,
Guild = 2
}
public enum StickerFormatType {
Png = 1,
Apng = 2,
Lottie = 3,
Gif = 4
}
@@ -38,7 +38,9 @@ public class IdentifyController(ILogger<IdentifyController> logger, SpacebarAuth
}
yield return new ReplicationMessage<ReadyResponse>() {
Payload = new() { },
Payload = new() {
Guilds = []
},
};
}