From b8c42bb22c38200666e02d61fbb0819d371d1546 Mon Sep 17 00:00:00 2001 From: yuzu Date: Thu, 1 May 2025 15:51:51 -0500 Subject: [PATCH] minor refactor --- build.zig | 4 +- src/{ => cache}/cache.zig | 22 +- src/config.zig | 1 + src/errors.zig | 2 +- src/http/api.zig | 0 src/{ => http}/http.zig | 6 +- src/{discord.zig => lib.zig} | 27 +- src/shard/bucket.zig | 106 ++ src/shard/connect_queue.zig | 87 ++ src/shard/intents.zig | 179 +++ src/{ => shard}/shard.zig | 44 +- src/{ => shard}/sharder.zig | 31 +- src/shard/util.zig | 59 + src/structures/application.zig | 2 +- src/structures/interaction.zig | 2 +- src/structures/partial.zig | 9 +- src/structures/shared.zig | 1699 ++++++++++------------- src/structures/types.zig | 2 - src/structures/user.zig | 2 +- src/{internal.zig => utils/core.zig} | 257 +--- src/{json-helper.zig => utils/json.zig} | 0 src/{extra => utils}/permissions.zig | 0 22 files changed, 1273 insertions(+), 1268 deletions(-) rename src/{ => cache}/cache.zig (90%) create mode 100644 src/http/api.zig rename src/{ => http}/http.zig (98%) rename src/{discord.zig => lib.zig} (97%) create mode 100644 src/shard/bucket.zig create mode 100644 src/shard/connect_queue.zig create mode 100644 src/shard/intents.zig rename src/{ => shard}/shard.zig (99%) rename src/{ => shard}/sharder.zig (91%) create mode 100644 src/shard/util.zig rename src/{internal.zig => utils/core.zig} (51%) rename src/{json-helper.zig => utils/json.zig} (100%) rename src/{extra => utils}/permissions.zig (100%) diff --git a/build.zig b/build.zig index cbdbe0d..a659a9e 100644 --- a/build.zig +++ b/build.zig @@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void { const zlib = b.dependency("zlib", .{}); const dzig = b.addModule("discord.zig", .{ - .root_source_file = b.path("src/discord.zig"), + .root_source_file = b.path("src/lib.zig"), .link_libc = true, }); @@ -47,7 +47,7 @@ pub fn build(b: *std.Build) void { const lib = b.addStaticLibrary(.{ .name = "discord.zig", - .root_source_file = b.path("src/discord.zig"), + .root_source_file = b.path("lib/discord.zig"), .target = target, .optimize = optimize, }); diff --git a/src/cache.zig b/src/cache/cache.zig similarity index 90% rename from src/cache.zig rename to src/cache/cache.zig index 5ed9d15..e2d939a 100644 --- a/src/cache.zig +++ b/src/cache/cache.zig @@ -4,23 +4,23 @@ const std = @import("std"); /// otherwise, simply do TableTemplate{} /// this is a template for the cache tables pub const TableTemplate = struct { - comptime User: type = @import("./config.zig").StoredUser, - comptime Guild: type = @import("./config.zig").StoredGuild, - comptime Channel: type = @import("./config.zig").StoredChannel, - comptime Emoji: type = @import("./config.zig").StoredEmoji, - comptime Message: type = @import("./config.zig").StoredMessage, - comptime Role: type = @import("./config.zig").StoredRole, - comptime Sticker: type = @import("./config.zig").StoredSticker, - comptime Reaction: type = @import("./config.zig").StoredReaction, - comptime Member: type = @import("./config.zig").StoredMember, - comptime Thread: type = @import("./config.zig").StoredChannel, + comptime User: type = @import("../config.zig").StoredUser, + comptime Guild: type = @import("../config.zig").StoredGuild, + comptime Channel: type = @import("../config.zig").StoredChannel, + comptime Emoji: type = @import("../config.zig").StoredEmoji, + comptime Message: type = @import("../config.zig").StoredMessage, + comptime Role: type = @import("../config.zig").StoredRole, + comptime Sticker: type = @import("../config.zig").StoredSticker, + comptime Reaction: type = @import("../config.zig").StoredReaction, + comptime Member: type = @import("../config.zig").StoredMember, + comptime Thread: type = @import("../config.zig").StoredChannel, }; // by default this caches everything // therefore we'll allow custom cache tables pub fn CacheTables(comptime Table: TableTemplate) type { return struct { - const Snowflake = @import("./structures/snowflake.zig").Snowflake; + const Snowflake = @import("../structures/snowflake.zig").Snowflake; const StoredUser: type = Table.User; const StoredGuild: type = Table.Guild; diff --git a/src/config.zig b/src/config.zig index 3f3f50e..0b45d7c 100644 --- a/src/config.zig +++ b/src/config.zig @@ -4,6 +4,7 @@ const PremiumTypes = @import("./structures/shared.zig").PremiumTypes; const Snowflake = @import("./structures/snowflake.zig").Snowflake; const AvatarDecorationData = @import("./structures/user.zig").AvatarDecorationData; + /// https://discord.com/developers/docs/resources/user#user-object /// modify this to your liking pub const StoredUser = struct { diff --git a/src/errors.zig b/src/errors.zig index e7ade3a..22d4bbd 100644 --- a/src/errors.zig +++ b/src/errors.zig @@ -29,5 +29,5 @@ pub const DiscordError = struct { }; pub fn Result(comptime T: type) type { - return @import("json-helper.zig").OwnedEither(DiscordError, T); + return @import("./utils/json.zig").OwnedEither(DiscordError, T); } diff --git a/src/http/api.zig b/src/http/api.zig new file mode 100644 index 0000000..e69de29 diff --git a/src/http.zig b/src/http/http.zig similarity index 98% rename from src/http.zig rename to src/http/http.zig index 35222e4..b647853 100644 --- a/src/http.zig +++ b/src/http/http.zig @@ -18,10 +18,10 @@ const std = @import("std"); const mem = std.mem; const http = std.http; const json = std.json; -const json_helpers = @import("json-helper.zig"); +const json_helpers = @import("../utils/json.zig"); -pub const Result = @import("errors.zig").Result; -pub const DiscordError = @import("errors.zig").DiscordError; +pub const Result = @import("../errors.zig").Result; +pub const DiscordError = @import("../errors.zig").DiscordError; pub const BASE_URL = "https://discord.com/api/v10"; diff --git a/src/discord.zig b/src/lib.zig similarity index 97% rename from src/discord.zig rename to src/lib.zig index 5fa89f1..23fe4fc 100644 --- a/src/discord.zig +++ b/src/lib.zig @@ -67,8 +67,6 @@ pub const PermissionStrings = @import("structures/types.zig").PermissionStrings; pub const GatewayCloseEventCodes = @import("structures/types.zig").GatewayCloseEventCodes; pub const GatewayOpcodes = @import("structures/types.zig").GatewayOpcodes; pub const GatewayDispatchEventNames = @import("structures/types.zig").GatewayDispatchEventNames; -pub const GatewayIntents = @import("structures/types.zig").GatewayIntents; -pub const Intents = @import("structures/types.zig").Intents; pub const InteractionResponseTypes = @import("structures/types.zig").InteractionResponseTypes; pub const SortOrderTypes = @import("structures/types.zig").SortOrderTypes; pub const ForumLayout = @import("structures/types.zig").ForumLayout; @@ -307,26 +305,26 @@ pub const ApplicationWebhook = @import("structures/types.zig").ApplicationWebhoo pub const GatewayPayload = @import("structures/types.zig").GatewayPayload; // END USING NAMESPACE -pub const CacheTables = @import("cache.zig").CacheTables; -pub const CacheLike = @import("cache.zig").CacheLike; -pub const DefaultCache = @import("cache.zig").DefaultCache; +pub const CacheTables = @import("cache/cache.zig").CacheTables; +pub const CacheLike = @import("cache/cache.zig").CacheLike; +pub const DefaultCache = @import("cache/cache.zig").DefaultCache; -pub const Permissions = @import("extra/permissions.zig").Permissions; -pub const Shard = @import("shard.zig").Shard; +pub const Permissions = @import("utils/permissions.zig").Permissions; +pub const Shard = @import("shard/shard.zig").Shard; pub const zjson = @compileError("Deprecated."); -pub const Internal = @import("internal.zig"); +pub const Internal = @import("utils/core.zig"); const GatewayDispatchEvent = Internal.GatewayDispatchEvent; -const GatewayBotInfo = Internal.GatewayBotInfo; +const GatewayBotInfo = @import("shard/util.zig").GatewayBotInfo; const Log = Internal.Log; // sharder -pub const Sharder = @import("sharder.zig").ShardManager; +pub const Sharder = @import("shard/sharder.zig").ShardManager; -pub const cache = @import("cache.zig"); +pub const cache = @import("cache/cache.zig"); -pub const FetchReq = @import("http.zig").FetchReq; -pub const FileData = @import("http.zig").FileData; +pub const FetchReq = @import("http/http.zig").FetchReq; +pub const FileData = @import("http/http.zig").FileData; const std = @import("std"); const mem = std.mem; @@ -421,6 +419,9 @@ pub fn deinit(self: *Session) void { self.deinit(); } +pub const GatewayIntents = @import("./shard/intents.zig").GatewayIntents; +pub const Intents = @import("./shard/intents.zig").Intents; + pub fn start(self: *Session, settings: struct { token: []const u8, intents: Intents, diff --git a/src/shard/bucket.zig b/src/shard/bucket.zig new file mode 100644 index 0000000..6c4b4eb --- /dev/null +++ b/src/shard/bucket.zig @@ -0,0 +1,106 @@ +const std = @import("std"); +const mem = std.mem; +const math = std.math; +const time = std.time; +const atomic = std.atomic; +const Thread = std.Thread; +const PriorityQueue = std.PriorityQueue; + +pub const Bucket = struct { + pub const RequestWithPrio = struct { + callback: *const fn () void, + priority: u32 = 1, + }; + + fn lessthan(_: void, a: RequestWithPrio, b: RequestWithPrio) math.Order { + return math.order(a.priority, b.priority); + } + + /// The queue of requests to acquire an available request. + /// Mapped by (shardId, RequestWithPrio) + queue: PriorityQueue(RequestWithPrio, void, lessthan), + + limit: usize, + refill_interval: u64, + refill_amount: usize, + + /// The amount of requests that have been used up already. + used: usize = 0, + + /// Whether or not the queue is already processing. + processing: bool = false, + + /// Whether the timeout should be killed because there is already one running + should_stop: atomic.Value(bool) = .init(false), + + /// The timestamp in milliseconds when the next refill is scheduled. + refills_at: ?u64 = null, + + pub fn init(allocator: mem.Allocator, limit: usize, refill_interval: u64, refill_amount: usize) Bucket { + return .{ + .queue = PriorityQueue(RequestWithPrio, void, lessthan).init(allocator, {}), + .limit = limit, + .refill_interval = refill_interval, + .refill_amount = refill_amount, + }; + } + + fn remaining(self: *Bucket) usize { + if (self.limit < self.used) { + return 0; + } else { + return self.limit - self.used; + } + } + + pub fn refill(self: *Bucket) Thread.SpawnError!void { + // Lower the used amount by the refill amount + self.used = if (self.refill_amount > self.used) 0 else self.used - self.refill_amount; + + // Reset the refills_at timestamp since it just got refilled + self.refills_at = null; + + if (self.used > 0) { + if (self.should_stop.load(.monotonic) == true) { + self.should_stop.store(false, .monotonic); + } + const thread = try Thread.spawn(.{}, Bucket.timeout, .{self}); + thread.detach; + self.refills_at = time.milliTimestamp() + self.refill_interval; + } + } + + fn timeout(self: *Bucket) void { + while (!self.should_stop.load(.monotonic)) { + self.refill(); + time.sleep(time.ns_per_ms * self.refill_interval); + } + } + + pub fn processQueue(self: *Bucket) std.Thread.SpawnError!void { + if (self.processing) return; + + while (self.queue.remove()) |first_element| { + if (self.remaining() != 0) { + first_element.callback(); + self.used += 1; + + if (!self.should_stop.load(.monotonic)) { + const thread = try Thread.spawn(.{}, Bucket.timeout, .{self}); + thread.detach; + self.refills_at = time.milliTimestamp() + self.refill_interval; + } + } else if (self.refills_at) |ra| { + const now = time.milliTimestamp(); + if (ra > now) time.sleep(time.ns_per_ms * (ra - now)); + } + } + + self.processing = false; + } + + pub fn acquire(self: *Bucket, rq: RequestWithPrio) !void { + try self.queue.add(rq); + try self.processQueue(); + } +}; diff --git a/src/shard/connect_queue.zig b/src/shard/connect_queue.zig new file mode 100644 index 0000000..92cc8e1 --- /dev/null +++ b/src/shard/connect_queue.zig @@ -0,0 +1,87 @@ +const std = @import("std"); +const mem = std.mem; + +/// inspired from: +/// https://github.com/tiramisulabs/seyfert/blob/main/src/websocket/structures/timeout.ts +pub fn ConnectQueue(comptime T: type) type { + return struct { + pub const RequestWithShard = struct { + callback: *const fn (self: *RequestWithShard) anyerror!void, + shard: T, + }; + + // ignore this function + // so it becomes a regular dequeue + fn eq(_: void, _: RequestWithShard, _: RequestWithShard) std.math.Order { + return std.math.Order.eq; + } + + dequeue: std.PriorityDequeue(RequestWithShard, void, eq), + allocator: mem.Allocator, + remaining: usize, + interval_time: u64 = 5000, + running: bool = false, + concurrency: usize = 1, + + pub fn init(allocator: mem.Allocator, concurrency: usize, interval_time: u64) !ConnectQueue(T) { + return .{ + .allocator = allocator, + .dequeue = std.PriorityDequeue(RequestWithShard, void, eq).init(allocator, {}), + .remaining = concurrency, + .interval_time = interval_time, + .concurrency = concurrency, + }; + } + + pub fn deinit(self: *ConnectQueue(T)) void { + self.dequeue.deinit(); + } + + pub fn push(self: *ConnectQueue(T), req: RequestWithShard) !void { + if (self.remaining == 0) { + return self.dequeue.add(req); + } + self.remaining -= 1; + + if (!self.running) { + try self.startInterval(); + self.running = true; + } + + if (self.dequeue.count() < self.concurrency) { + // perhaps store this? + const ptr = try self.allocator.create(RequestWithShard); + ptr.* = req; + try req.callback(ptr); + return; + } + + return self.dequeue.add(req); + } + + fn startInterval(self: *ConnectQueue(T)) !void { + while (self.running) { + std.Thread.sleep(std.time.ns_per_ms * (self.interval_time / self.concurrency)); + const req: ?RequestWithShard = self.dequeue.removeMin(); // pop front + + while (self.dequeue.count() == 0 and req == null) {} + + if (req) |r| { + const ptr = try self.allocator.create(RequestWithShard); + ptr.* = r; + try @call(.auto, r.callback, .{ptr}); + return; + } + + if (self.remaining < self.concurrency) { + self.remaining += 1; + } + + if (self.dequeue.count() == 0) { + self.running = false; + } + } + } + }; +} + diff --git a/src/shard/intents.zig b/src/shard/intents.zig new file mode 100644 index 0000000..a328f1a --- /dev/null +++ b/src/shard/intents.zig @@ -0,0 +1,179 @@ +const std = @import("std"); +const mem = std.mem; +const json = std.json; + +/// https://discord.com/developers/docs/topics/gateway#list-of-intents +pub const GatewayIntents = packed struct { + pub fn toRaw(self: GatewayIntents) u32 { + return @bitCast(self); + } + + pub fn fromRaw(raw: u32) GatewayIntents { + return @bitCast(raw); + } + + pub fn jsonParse(allocator: mem.Allocator, src: anytype, _: json.ParseOptions) !@This() { + const value = try json.innerParse(json.Value, allocator, src, .{ + .ignore_unknown_fields = true, + .max_value_len = 0x1000, + }); + if (value != .integer) @panic("Invalid value for bitfield"); + + return fromRaw(@intCast(value.integer)); + } + + pub fn jsonParseFromValue(_: mem.Allocator, src: json.Value, _: json.ParseOptions) @This() { + if (src != .integer) @panic("Invalid value for bitfield"); + return fromRaw(@intCast(src.integer)); + } + + /// + /// - GUILD_CREATE + /// - GUILD_UPDATE + /// - GUILD_DELETE + /// - GUILD_ROLE_CREATE + /// - GUILD_ROLE_UPDATE + /// - GUILD_ROLE_DELETE + /// - CHANNEL_CREATE + /// - CHANNEL_UPDATE + /// - CHANNEL_DELETE + /// - CHANNEL_PINS_UPDATE + /// - THREAD_CREATE + /// - THREAD_UPDATE + /// - THREAD_DELETE + /// - THREAD_LIST_SYNC + /// - THREAD_MEMBER_UPDATE + /// - THREAD_MEMBERS_UPDATE + /// - STAGE_INSTANCE_CREATE + /// - STAGE_INSTANCE_UPDATE + /// - STAGE_INSTANCE_DELETE + //// + Guilds: bool = false, + /// + /// - GUILD_MEMBER_ADD + /// - GUILD_MEMBER_UPDATE + /// - GUILD_MEMBER_REMOVE + /// - THREAD_MEMBERS_UPDATE + /// + /// This is a privileged intent. + //// + GuildMembers: bool = false, + /// + /// - GUILD_AUDIT_LOG_ENTRY_CREATE + /// - GUILD_BAN_ADD + /// - GUILD_BAN_REMOVE + //// + GuildModeration: bool = false, + /// + /// - GUILD_EMOJIS_UPDATE + /// - GUILD_STICKERS_UPDATE + //// + GuildEmojisAndStickers: bool = false, + /// + /// - GUILD_INTEGRATIONS_UPDATE + /// - INTEGRATION_CREATE + /// - INTEGRATION_UPDATE + /// - INTEGRATION_DELETE + //// + GuildIntegrations: bool = false, + /// + /// - WEBHOOKS_UPDATE + //// + GuildWebhooks: bool = false, + /// + /// - INVITE_CREATE + /// - INVITE_DELETE + //// + GuildInvites: bool = false, + /// + /// - VOICE_STATE_UPDATE + /// - VOICE_CHANNEL_EFFECT_SEND + //// + GuildVoiceStates: bool = false, + /// + /// - PRESENCE_UPDATE + /// + /// This is a privileged intent. + //// + GuildPresences: bool = false, + /// + /// - MESSAGE_CREATE + /// - MESSAGE_UPDATE + /// - MESSAGE_DELETE + /// - MESSAGE_DELETE_BULK + /// + /// The messages do not contain content by default. + /// If you want to receive their content too, you need to turn on the privileged `MESSAGE_CONTENT` intent. */ + GuildMessages: bool = false, + /// + /// - MESSAGE_REACTION_ADD + /// - MESSAGE_REACTION_REMOVE + /// - MESSAGE_REACTION_REMOVE_ALL + /// - MESSAGE_REACTION_REMOVE_EMOJI + //// + GuildMessageReactions: bool = false, + /// + /// - TYPING_START + //// + GuildMessageTyping: bool = false, + /// + /// - CHANNEL_CREATE + /// - MESSAGE_CREATE + /// - MESSAGE_UPDATE + /// - MESSAGE_DELETE + /// - CHANNEL_PINS_UPDATE + //// + DirectMessages: bool = false, + /// + /// - MESSAGE_REACTION_ADD + /// - MESSAGE_REACTION_REMOVE + /// - MESSAGE_REACTION_REMOVE_ALL + /// - MESSAGE_REACTION_REMOVE_EMOJI + //// + DirectMessageReactions: bool = false, + /// + /// - TYPING_START + //// + DirectMessageTyping: bool = false, + /// + /// This intent will add all content related values to message events. + /// + /// This is a privileged intent. + //// + MessageContent: bool = false, + /// + /// - GUILD_SCHEDULED_EVENT_CREATE + /// - GUILD_SCHEDULED_EVENT_UPDATE + /// - GUILD_SCHEDULED_EVENT_DELETE + /// - GUILD_SCHEDULED_EVENT_USER_ADD this is experimental and unstable. + /// - GUILD_SCHEDULED_EVENT_USER_REMOVE this is experimental and unstable. + //// + GuildScheduledEvents: bool = false, + _pad: u4 = 0, + /// + /// - AUTO_MODERATION_RULE_CREATE + /// - AUTO_MODERATION_RULE_UPDATE + /// - AUTO_MODERATION_RULE_DELETE + //// + AutoModerationConfiguration: bool = false, + /// + /// - AUTO_MODERATION_ACTION_EXECUTION + //// + AutoModerationExecution: bool = false, + _pad2: u3 = 0, + /// + /// - MESSAGE_POLL_VOTE_ADD + /// - MESSAGE_POLL_VOTE_REMOVE + //// + GuildMessagePolls: bool = false, + /// + /// - MESSAGE_POLL_VOTE_ADD + /// - MESSAGE_POLL_VOTE_REMOVE + //// + DirectMessagePolls: bool = false, + _pad3: u4 = 0, +}; + +/// https://discord.com/developers/docs/topics/gateway#list-of-intents +/// alias +pub const Intents = GatewayIntents; diff --git a/src/shard.zig b/src/shard/shard.zig similarity index 99% rename from src/shard.zig rename to src/shard/shard.zig index 9978ab4..2f1fa14 100644 --- a/src/shard.zig +++ b/src/shard/shard.zig @@ -28,29 +28,31 @@ const http = std.http; const zlib = @import("zlib"); const json = @import("std").json; -const Result = @import("errors.zig").Result; +const Result = @import("../errors.zig").Result; -const IdentifyProperties = @import("internal.zig").IdentifyProperties; -const GatewayInfo = @import("internal.zig").GatewayInfo; -const GatewayBotInfo = @import("internal.zig").GatewayBotInfo; -const GatewaySessionStartLimit = @import("internal.zig").GatewaySessionStartLimit; -const ShardDetails = @import("internal.zig").ShardDetails; -const internalLogif = @import("internal.zig").logif; +const IdentifyProperties = @import("util.zig").IdentifyProperties; +const GatewayInfo = @import("util.zig").GatewayInfo; +const GatewayBotInfo = @import("util.zig").GatewayBotInfo; +const GatewaySessionStartLimit = @import("util.zig").GatewaySessionStartLimit; +const ShardDetails = @import("util.zig").ShardDetails; +const internalLogif = @import("../utils/core.zig").logif; -const Log = @import("internal.zig").Log; -const GatewayDispatchEvent = @import("internal.zig").GatewayDispatchEvent; -const Bucket = @import("internal.zig").Bucket; -const default_identify_properties = @import("internal.zig").default_identify_properties; +const Log = @import("../utils/core.zig").Log; +const GatewayDispatchEvent = @import("../utils/core.zig").GatewayDispatchEvent; +const Bucket = @import("bucket.zig").Bucket; +const default_identify_properties = @import("util.zig").default_identify_properties; -const Types = @import("./structures/types.zig"); +const Types = @import("../structures/types.zig"); const Opcode = Types.GatewayOpcodes; -const Intents = Types.Intents; +const Intents = @import("intents.zig").Intents; const Snowflake = Types.Snowflake; -const FetchReq = @import("http.zig").FetchReq; -const MakeRequestError = @import("http.zig").MakeRequestError; +const FetchReq = @import("../http/http.zig").FetchReq; +const MakeRequestError = @import("../http/http.zig").MakeRequestError; const Partial = Types.Partial; -const TableTemplate = @import("cache.zig").TableTemplate; +const TableTemplate = @import("../cache/cache.zig").TableTemplate; +const CacheTables = @import("../cache/cache.zig").CacheTables; +const FileData = @import("../http/http.zig").FileData; pub fn Shard(comptime Table: TableTemplate) type { return struct { @@ -106,7 +108,7 @@ pub fn Shard(comptime Table: TableTemplate) type { log: Log = .no, /// actual cache - cache_handler: *@import("cache.zig").CacheTables(Table), + cache_handler: *CacheTables(Table), pub fn resumable(self: *Self) bool { return self.resume_gateway_url != null and @@ -160,7 +162,7 @@ pub fn Shard(comptime Table: TableTemplate) type { options: ShardOptions, run: GatewayDispatchEvent, log: Log, - cache: *@import("cache.zig").CacheTables(Table), + cache: *CacheTables(Table), sharder_pool: ?*std.Thread.Pool = null, }) zlib.Error!Self { return Self{ @@ -933,7 +935,7 @@ pub fn Shard(comptime Table: TableTemplate) type { /// the create message payload create_message: Partial(Types.CreateMessage), /// the files to send, must be one of FileData.type - files: []@import("http.zig").FileData, + files: []FileData, }; /// same as `sendMessage` but acceps a files field @@ -1448,7 +1450,7 @@ pub fn Shard(comptime Table: TableTemplate) type { pub const StartThreadInForumOrMediaChannelWithFiles = struct { start_thread: Types.StartThreadFromMessage, - files: []@import("http.zig").FileData, + files: []FileData, }; /// same as `startThreadInForumOrMediaChannel` @@ -2862,7 +2864,7 @@ pub fn Shard(comptime Table: TableTemplate) type { self: *Self, guild_id: Snowflake, sticker: Types.CreateModifyGuildSticker, - file: @import("http.zig").FileData, + file: FileData, ) RequestFailedError!Result(Types.Sticker) { var buf: [256]u8 = undefined; const path = try std.fmt.bufPrint(&buf, "/guilds/{d}/stickers", .{guild_id.into()}); diff --git a/src/sharder.zig b/src/shard/sharder.zig similarity index 91% rename from src/sharder.zig rename to src/shard/sharder.zig index 078ad6c..b1bfa7a 100644 --- a/src/sharder.zig +++ b/src/shard/sharder.zig @@ -14,20 +14,21 @@ //! OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR //! PERFORMANCE OF THIS SOFTWARE. -const Intents = @import("./structures/types.zig").Intents; -const Snowflake = @import("./structures/snowflake.zig").Snowflake; -const GatewayBotInfo = @import("internal.zig").GatewayBotInfo; -const IdentifyProperties = @import("internal.zig").IdentifyProperties; -const internalLogif = @import("internal.zig").logif; -const ShardDetails = @import("internal.zig").ShardDetails; -const ConnectQueue = @import("internal.zig").ConnectQueue; -const GatewayDispatchEvent = @import("internal.zig").GatewayDispatchEvent; -const Log = @import("internal.zig").Log; +const Intents = @import("intents.zig").Intents; +const Snowflake = @import("../structures/snowflake.zig").Snowflake; +const GatewayBotInfo = @import("util.zig").GatewayBotInfo; +const IdentifyProperties = @import("util.zig").IdentifyProperties; +const internalLogif = @import("../utils/core.zig").logif; +const ShardDetails = @import("util.zig").ShardDetails; +const ConnectQueue = @import("connect_queue.zig").ConnectQueue; +const GatewayDispatchEvent = @import("../utils/core.zig").GatewayDispatchEvent; +const Log = @import("../utils/core.zig").Log; const Shard = @import("shard.zig").Shard; const std = @import("std"); const mem = std.mem; -const debug = @import("internal.zig").debug; -const TableTemplate = @import("cache.zig").TableTemplate; +const debug = @import("../utils/core.zig").debug; +const TableTemplate = @import("../cache/cache.zig").TableTemplate; +const CacheTables = @import("../cache/cache.zig").CacheTables; pub fn ShardManager(comptime Table: TableTemplate) type { return struct { @@ -50,7 +51,7 @@ pub fn ShardManager(comptime Table: TableTemplate) type { log: Log, // must be initialised - cache: *@import("cache.zig").CacheTables(Table), + cache: *CacheTables(Table), pub const ShardData = struct { /// resume seq to resume connections @@ -87,11 +88,11 @@ pub fn ShardManager(comptime Table: TableTemplate) type { options: SessionOptions, run: GatewayDispatchEvent, log: Log, - cache: @import("cache.zig").TableTemplate, + cache: TableTemplate, }) mem.Allocator.Error!Self { const concurrency = settings.options.info.session_start_limit.?.max_concurrency; - const cache = try allocator.create(@import("cache.zig").CacheTables(Table)); - cache.* = @import("cache.zig").CacheTables(Table).defaults(allocator); + const cache = try allocator.create(CacheTables(Table)); + cache.* = CacheTables(Table).defaults(allocator); return .{ .allocator = allocator, diff --git a/src/shard/util.zig b/src/shard/util.zig new file mode 100644 index 0000000..049071b --- /dev/null +++ b/src/shard/util.zig @@ -0,0 +1,59 @@ +pub const IdentifyProperties = struct { + /// Operating system the shard runs on. + os: []const u8, + /// The "browser" where this shard is running on. + browser: []const u8, + /// The device on which the shard is running. + device: []const u8, +}; + +pub const default_identify_properties = IdentifyProperties{ + .os = @tagName(@import("builtin").os.tag), + .browser = "discord.zig", + .device = "discord.zig", +}; + +/// https://discord.com/developers/docs/topics/gateway#get-gateway +pub const GatewayInfo = struct { + /// The WSS URL that can be used for connecting to the gateway + url: []const u8, +}; + +/// https://discord.com/developers/docs/events/gateway#session-start-limit-object +pub const GatewaySessionStartLimit = struct { + /// Total number of session starts the current user is allowed + total: u32, + /// Remaining number of session starts the current user is allowed + remaining: u32, + /// Number of milliseconds after which the limit resets + reset_after: u32, + /// Number of identify requests allowed per 5 seconds + max_concurrency: u32, +}; + +/// https://discord.com/developers/docs/topics/gateway#get-gateway-bot +pub const GatewayBotInfo = struct { + url: []const u8, + /// The recommended number of shards to use when connecting + /// + /// See https://discord.com/developers/docs/topics/gateway#sharding + shards: u32, + /// Information on the current session start limit + /// + /// See https://discord.com/developers/docs/topics/gateway#session-start-limit-object + session_start_limit: ?GatewaySessionStartLimit, +}; + +pub const ShardDetails = struct { + /// Bot token which is used to connect to Discord */ + token: []const u8, + /// The URL of the gateway which should be connected to. + url: []const u8 = "wss://gateway.discord.gg", + /// The gateway version which should be used. + version: ?usize = 10, + /// The calculated intent value of the events which the shard should receive. + intents: @import("./intents.zig").Intents, + /// Identify properties to use + properties: IdentifyProperties = default_identify_properties, +}; + diff --git a/src/structures/application.zig b/src/structures/application.zig index 8861be3..849931a 100644 --- a/src/structures/application.zig +++ b/src/structures/application.zig @@ -21,7 +21,7 @@ const Partial = @import("partial.zig").Partial; const User = @import("user.zig").User; const Team = @import("team.zig").Team; const Guild = @import("guild.zig").Guild; -const AssociativeArray = @import("../json-helper.zig").AssociativeArray; +const AssociativeArray = @import("../utils/json.zig").AssociativeArray; /// https://discord.com/developers/docs/resources/application#application-object pub const Application = struct { diff --git a/src/structures/interaction.zig b/src/structures/interaction.zig index af7112f..360ccfb 100644 --- a/src/structures/interaction.zig +++ b/src/structures/interaction.zig @@ -32,7 +32,7 @@ const InteractionResponseTypes = @import("shared.zig").InteractionResponseTypes; const InteractionContextType = @import("command.zig").InteractionContextType; const Entitlement = @import("monetization.zig").Entitlement; - const Record = @import("../json-helper.zig").Record; + const Record = @import("../utils/json.zig").Record; pub const Interaction = struct { /// Id of the interaction diff --git a/src/structures/partial.zig b/src/structures/partial.zig index a0ef827..1f14c90 100644 --- a/src/structures/partial.zig +++ b/src/structures/partial.zig @@ -15,12 +15,13 @@ //! PERFORMANCE OF THIS SOFTWARE. const std = @import("std"); +const builtin = std.builtin; pub fn Partial(comptime T: type) type { const info = @typeInfo(T); switch (info) { .@"struct" => |s| { - comptime var fields: []const std.builtin.Type.StructField = &[_]std.builtin.Type.StructField{}; + comptime var fields: []const builtin.Type.StructField = &[_]builtin.Type.StructField{}; inline for (s.fields) |field| { if (field.is_comptime) { @compileError("Cannot make Partial of " ++ @typeName(T) ++ ", it has a comptime field " ++ field.name); @@ -31,7 +32,7 @@ pub fn Partial(comptime T: type) type { }; const default_value: optional_type = null; const aligned_ptr: *align(field.alignment) const anyopaque = @alignCast(@ptrCast(&default_value)); - const optional_field: [1]std.builtin.Type.StructField = [_]std.builtin.Type.StructField{.{ + const optional_field: [1]builtin.Type.StructField = [_]builtin.Type.StructField{.{ .alignment = field.alignment, .default_value_ptr = aligned_ptr, .is_comptime = false, @@ -40,9 +41,9 @@ pub fn Partial(comptime T: type) type { }}; fields = fields ++ optional_field; } - const partial_type_info: std.builtin.Type = .{ .@"struct" = .{ + const partial_type_info: builtin.Type = .{ .@"struct" = .{ .backing_integer = s.backing_integer, - .decls = &[_]std.builtin.Type.Declaration{}, + .decls = &[_]builtin.Type.Declaration{}, .fields = fields, .is_tuple = s.is_tuple, .layout = s.layout, diff --git a/src/structures/shared.zig b/src/structures/shared.zig index 354338a..046d51d 100644 --- a/src/structures/shared.zig +++ b/src/structures/shared.zig @@ -637,53 +637,53 @@ pub const GuildFeatures = enum { FEATURABLE, /// Guild has access to set an animated guild icon ANIMATED_ICON, - /// Guild has access to set a guild banner image - BANNER, - /// Guild has enabled the welcome screen - WELCOME_SCREEN_ENABLED, - /// Guild has enabled [Membership Screening](https://discord.com/developers/docs/resources/guild#membership-screening-object) - MEMBER_VERIFICATION_GATE_ENABLED, - /// Guild can be previewed before joining via Membership Screening or the directory - PREVIEW_ENABLED, - /// Guild has enabled ticketed events - TICKETED_EVENTS_ENABLED, - /// Guild has increased custom sticker slots - MORE_STICKERS, - /// Guild is able to set role icons - ROLE_ICONS, - /// Guild has role subscriptions that can be purchased. - ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE, - /// Guild has enabled role subscriptions. - ROLE_SUBSCRIPTIONS_ENABLED, - /// Guild has set up auto moderation rules - AUTO_MODERATION, - /// Guild has paused invites, preventing new users from joining - INVITES_DISABLED, - /// Guild has access to set an animated guild banner image - ANIMATED_BANNER, - /// Guild has disabled alerts for join raids in the configured safety alerts channel - RAID_ALERTS_DISABLED, - /// Guild is using the old permissions configuration behavior - APPLICATION_COMMAND_PERMISSIONS_V2, - }; + /// Guild has access to set a guild banner image + BANNER, + /// Guild has enabled the welcome screen + WELCOME_SCREEN_ENABLED, + /// Guild has enabled [Membership Screening](https://discord.com/developers/docs/resources/guild#membership-screening-object) + MEMBER_VERIFICATION_GATE_ENABLED, + /// Guild can be previewed before joining via Membership Screening or the directory + PREVIEW_ENABLED, + /// Guild has enabled ticketed events + TICKETED_EVENTS_ENABLED, + /// Guild has increased custom sticker slots + MORE_STICKERS, + /// Guild is able to set role icons + ROLE_ICONS, + /// Guild has role subscriptions that can be purchased. + ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE, + /// Guild has enabled role subscriptions. + ROLE_SUBSCRIPTIONS_ENABLED, + /// Guild has set up auto moderation rules + AUTO_MODERATION, + /// Guild has paused invites, preventing new users from joining + INVITES_DISABLED, + /// Guild has access to set an animated guild banner image + ANIMATED_BANNER, + /// Guild has disabled alerts for join raids in the configured safety alerts channel + RAID_ALERTS_DISABLED, + /// Guild is using the old permissions configuration behavior + APPLICATION_COMMAND_PERMISSIONS_V2, +}; - /// https://discord.com/developers/docs/resources/guild#guild-object-mfa-level - pub const MfaLevels = enum { - /// Guild has no MFA/2FA requirement for moderation actions - None, - /// Guild has a 2FA requirement for moderation actions - Elevated, - }; +/// https://discord.com/developers/docs/resources/guild#guild-object-mfa-level +pub const MfaLevels = enum { + /// Guild has no MFA/2FA requirement for moderation actions + None, + /// Guild has a 2FA requirement for moderation actions + Elevated, +}; - /// https://discord.com/developers/docs/resources/guild#guild-object-system-channel-flags - pub const SystemChannelFlags = packed struct { - pub fn toRaw(self: SystemChannelFlags) u8 { - return @bitCast(self); - } +/// https://discord.com/developers/docs/resources/guild#guild-object-system-channel-flags +pub const SystemChannelFlags = packed struct { + pub fn toRaw(self: SystemChannelFlags) u8 { + return @bitCast(self); + } - pub fn fromRaw(raw: u8) SystemChannelFlags { - return @bitCast(raw); - } + pub fn fromRaw(raw: u8) SystemChannelFlags { + return @bitCast(raw); + } pub fn jsonParse(allocator: std.mem.Allocator, src: anytype, _: std.json.ParseOptions) !@This() { const value = try std.json.innerParse(std.json.Value, allocator, src, .{ @@ -701,46 +701,46 @@ pub const GuildFeatures = enum { } - /// Suppress member join notifications - SuppressJoinNotifications: bool = false, - /// Suppress server boost notifications - SuppressPremiumSubscriptions: bool = false, - /// Suppress server setup tips - SuppressGuildReminderNotifications: bool = false, - /// Hide member join sticker reply buttons - SuppressJoinNotificationReplies: bool = false, - _pad: u4 = 0, - }; + /// Suppress member join notifications + SuppressJoinNotifications: bool = false, + /// Suppress server boost notifications + SuppressPremiumSubscriptions: bool = false, + /// Suppress server setup tips + SuppressGuildReminderNotifications: bool = false, + /// Hide member join sticker reply buttons + SuppressJoinNotificationReplies: bool = false, + _pad: u4 = 0, +}; - /// https://discord.com/developers/docs/resources/guild#guild-object-premium-tier - pub const PremiumTiers = enum { - /// Guild has not unlocked any Server Boost perks - None, - /// Guild has unlocked Server Boost level 1 perks - Tier1, - /// Guild has unlocked Server Boost level 2 perks - Tier2, - /// Guild has unlocked Server Boost level 3 perks - Tier3, - }; +/// https://discord.com/developers/docs/resources/guild#guild-object-premium-tier +pub const PremiumTiers = enum { + /// Guild has not unlocked any Server Boost perks + None, + /// Guild has unlocked Server Boost level 1 perks + Tier1, + /// Guild has unlocked Server Boost level 2 perks + Tier2, + /// Guild has unlocked Server Boost level 3 perks + Tier3, +}; - /// https://discord.com/developers/docs/resources/guild#guild-object-guild-nsfw-level - pub const GuildNsfwLevel = enum { - Default, - Explicit, - Safe, - AgeRestricted, - }; +/// https://discord.com/developers/docs/resources/guild#guild-object-guild-nsfw-level +pub const GuildNsfwLevel = enum { + Default, + Explicit, + Safe, + AgeRestricted, +}; - /// https://discord.com/developers/docs/resources/channel#channel-object-channel-types - pub const ChannelTypes = packed struct { - pub fn toRaw(self: ChannelTypes) u32 { - return @bitCast(self); - } +/// https://discord.com/developers/docs/resources/channel#channel-object-channel-types +pub const ChannelTypes = packed struct { + pub fn toRaw(self: ChannelTypes) u32 { + return @bitCast(self); + } - pub fn fromRaw(raw: u32) ChannelTypes { - return @bitCast(raw); - } + pub fn fromRaw(raw: u32) ChannelTypes { + return @bitCast(raw); + } pub fn jsonParse(allocator: std.mem.Allocator, src: anytype, _: std.json.ParseOptions) !@This() { const value = try std.json.innerParse(std.json.Value, allocator, src, .{ @@ -758,328 +758,328 @@ pub const GuildFeatures = enum { } - /// A text channel within a server - GuildText: bool = false, - /// A direct message between users - DM: bool = false, - /// A voice channel within a server - GuildVoice: bool = false, - /// A direct message between multiple users - GroupDm: bool = false, - /// An organizational category that contains up to 50 channels - GuildCategory: bool = false, - /// A channel that users can follow and crosspost into their own server - GuildAnnouncement: bool = false, - _pad: u4 = 0, - /// A temporary sub-channel within a GUILD_ANNOUNCEMENT channel - AnnouncementThread: bool = false, - /// A temporary sub-channel within a GUILD_TEXT or GUILD_FORUM channel - PublicThread: bool = false, - /// A temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission - PrivateThread: bool = false, - /// A voice channel for hosting events with an audience - GuildStageVoice: bool = false, - /// A channel in a hub containing the listed servers - GuildDirectory: bool = false, - /// A channel which can only contains threads - GuildForum: bool = false, - /// Channel that can only contain threads, similar to GUILD_FORUM channels - GuildMedia: bool = false, - _pad1: u15 = 0, - }; + /// A text channel within a server + GuildText: bool = false, + /// A direct message between users + DM: bool = false, + /// A voice channel within a server + GuildVoice: bool = false, + /// A direct message between multiple users + GroupDm: bool = false, + /// An organizational category that contains up to 50 channels + GuildCategory: bool = false, + /// A channel that users can follow and crosspost into their own server + GuildAnnouncement: bool = false, + _pad: u4 = 0, + /// A temporary sub-channel within a GUILD_ANNOUNCEMENT channel + AnnouncementThread: bool = false, + /// A temporary sub-channel within a GUILD_TEXT or GUILD_FORUM channel + PublicThread: bool = false, + /// A temporary sub-channel within a GUILD_TEXT channel that is only viewable by those invited and those with the MANAGE_THREADS permission + PrivateThread: bool = false, + /// A voice channel for hosting events with an audience + GuildStageVoice: bool = false, + /// A channel in a hub containing the listed servers + GuildDirectory: bool = false, + /// A channel which can only contains threads + GuildForum: bool = false, + /// Channel that can only contain threads, similar to GUILD_FORUM channels + GuildMedia: bool = false, + _pad1: u15 = 0, +}; - pub const OverwriteTypes = enum { - Role, - Member, - }; +pub const OverwriteTypes = enum { + Role, + Member, +}; - pub const VideoQualityModes = enum(u4) { - /// Discord chooses the quality for optimal performance - Auto = 1, - /// 720p - Full, - }; +pub const VideoQualityModes = enum(u4) { + /// Discord chooses the quality for optimal performance + Auto = 1, + /// 720p + Full, +}; - /// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types - pub const ActivityTypes = enum(u4) { - Playing = 0, - Streaming = 1, - Listening = 2, - Watching = 3, - Custom = 4, - Competing = 5, - }; +/// https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types +pub const ActivityTypes = enum(u4) { + Playing = 0, + Streaming = 1, + Listening = 2, + Watching = 3, + Custom = 4, + Competing = 5, +}; - /// https://discord.com/developers/docs/resources/channel#message-object-message-types - pub const MessageTypes = enum(u8) { - Default, - RecipientAdd, - RecipientRemove, - Call, - ChannelNameChange, - ChannelIconChange, - ChannelPinnedMessage, - UserJoin, - GuildBoost, - GuildBoostTier1, - GuildBoostTier2, - GuildBoostTier3, - ChannelFollowAdd, - GuildDiscoveryDisqualified = 14, - GuildDiscoveryRequalified, - GuildDiscoveryGracePeriodInitialWarning, - GuildDiscoveryGracePeriodFinalWarning, - ThreadCreated, - Reply, - ChatInputCommand, - ThreadStarterMessage, - GuildInviteReminder, - ContextMenuCommand, - AutoModerationAction, - RoleSubscriptionPurchase, - InteractionPremiumUpsell, - StageStart, - StageEnd, - StageSpeaker, - StageTopic = 31, - GuildApplicationPremiumSubscription, - GuildIncidentAlertModeEnabled = 36, - GuildIncidentAlertModeDisabled, - GuildIncidentReportRaid, - GuildIncidentReportFalseAlarm, - PurchaseNotification = 44, - PollResult = 46, - }; +/// https://discord.com/developers/docs/resources/channel#message-object-message-types +pub const MessageTypes = enum(u8) { + Default, + RecipientAdd, + RecipientRemove, + Call, + ChannelNameChange, + ChannelIconChange, + ChannelPinnedMessage, + UserJoin, + GuildBoost, + GuildBoostTier1, + GuildBoostTier2, + GuildBoostTier3, + ChannelFollowAdd, + GuildDiscoveryDisqualified = 14, + GuildDiscoveryRequalified, + GuildDiscoveryGracePeriodInitialWarning, + GuildDiscoveryGracePeriodFinalWarning, + ThreadCreated, + Reply, + ChatInputCommand, + ThreadStarterMessage, + GuildInviteReminder, + ContextMenuCommand, + AutoModerationAction, + RoleSubscriptionPurchase, + InteractionPremiumUpsell, + StageStart, + StageEnd, + StageSpeaker, + StageTopic = 31, + GuildApplicationPremiumSubscription, + GuildIncidentAlertModeEnabled = 36, + GuildIncidentAlertModeDisabled, + GuildIncidentReportRaid, + GuildIncidentReportFalseAlarm, + PurchaseNotification = 44, + PollResult = 46, +}; - /// https://discord.com/developers/docs/resources/channel#message-object-message-activity-types - pub const MessageActivityTypes = enum(u4) { - Join = 1, - Spectate = 2, - Listen = 3, - JoinRequest = 5, - }; +/// https://discord.com/developers/docs/resources/channel#message-object-message-activity-types +pub const MessageActivityTypes = enum(u4) { + Join = 1, + Spectate = 2, + Listen = 3, + JoinRequest = 5, +}; - /// https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-types - pub const StickerTypes = enum(u4) { - /// an official sticker in a pack - Standard = 1, - /// a sticker uploaded to a guild for the guild's members - Guild = 2, - }; +/// https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-types +pub const StickerTypes = enum(u4) { + /// an official sticker in a pack + Standard = 1, + /// a sticker uploaded to a guild for the guild's members + Guild = 2, +}; - /// https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-format-types - pub const StickerFormatTypes = enum(u4) { - Png = 1, - APng, - Lottie, - Gif, - }; +/// https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-format-types +pub const StickerFormatTypes = enum(u4) { + Png = 1, + APng, + Lottie, + Gif, +}; - /// https://discord.com/developers/docs/interactions/slash-commands#interaction-interactiontype - pub const InteractionTypes = enum(u4) { - Ping = 1, - ApplicationCommand = 2, - MessageComponent = 3, - ApplicationCommandAutocomplete = 4, - ModalSubmit = 5, - }; +/// https://discord.com/developers/docs/interactions/slash-commands#interaction-interactiontype +pub const InteractionTypes = enum(u4) { + Ping = 1, + ApplicationCommand = 2, + MessageComponent = 3, + ApplicationCommandAutocomplete = 4, + ModalSubmit = 5, +}; - /// https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoptiontype - pub const ApplicationCommandOptionTypes = enum(u4) { - SubCommand = 1, - SubCommandGroup, - String, - Integer, - Boolean, - User, - Channel, - Role, - Mentionable, - Number, - Attachment, - }; +/// https://discord.com/developers/docs/interactions/slash-commands#applicationcommandoptiontype +pub const ApplicationCommandOptionTypes = enum(u4) { + SubCommand = 1, + SubCommandGroup, + String, + Integer, + Boolean, + User, + Channel, + Role, + Mentionable, + Number, + Attachment, +}; - /// https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-events - pub const AuditLogEvents = enum(u4) { - /// Server settings were updated - GuildUpdate = 1, - /// Channel was created - ChannelCreate = 10, - /// Channel settings were updated - ChannelUpdate, - /// Channel was deleted - ChannelDelete, - /// Permission overwrite was added to a channel - ChannelOverwriteCreate, - /// Permission overwrite was updated for a channel - ChannelOverwriteUpdate, - /// Permission overwrite was deleted from a channel - ChannelOverwriteDelete, - /// Member was removed from server - MemberKick = 20, - /// Members were pruned from server - MemberPrune, - /// Member was banned from server - MemberBanAdd, - /// Server ban was lifted for a member - MemberBanRemove, - /// Member was updated in server - MemberUpdate, - /// Member was added or removed from a role - MemberRoleUpdate, - /// Member was moved to a different voice channel - MemberMove, - /// Member was disconnected from a voice channel - MemberDisconnect, - /// Bot user was added to server - BotAdd, - /// Role was created - RoleCreate = 30, - /// Role was edited - RoleUpdate, - /// Role was deleted - RoleDelete, - /// Server invite was created - InviteCreate = 40, - /// Server invite was updated - InviteUpdate, - /// Server invite was deleted - InviteDelete, - /// Webhook was created - WebhookCreate = 50, - /// Webhook properties or channel were updated - WebhookUpdate, - /// Webhook was deleted - WebhookDelete, - /// Emoji was created - EmojiCreate = 60, - /// Emoji name was updated - EmojiUpdate, - /// Emoji was deleted - EmojiDelete, - /// Single message was deleted - MessageDelete = 72, - /// Multiple messages were deleted - MessageBulkDelete, - /// Messaged was pinned to a channel - MessagePin, - /// Message was unpinned from a channel - MessageUnpin, - /// App was added to server - IntegrationCreate = 80, - /// App was updated (as an example, its scopes were updated) - IntegrationUpdate, - /// App was removed from server - IntegrationDelete, - /// Stage instance was created (stage channel becomes live) - StageInstanceCreate, - /// Stage instace details were updated - StageInstanceUpdate, - /// Stage instance was deleted (stage channel no longer live) - StageInstanceDelete, - /// Sticker was created - StickerCreate = 90, - /// Sticker details were updated - StickerUpdate, - /// Sticker was deleted - StickerDelete, - /// Event was created - GuildScheduledEventCreate = 100, - /// Event was updated - GuildScheduledEventUpdate, - /// Event was cancelled - GuildScheduledEventDelete, - /// Thread was created in a channel - ThreadCreate = 110, - /// Thread was updated - ThreadUpdate, - /// Thread was deleted - ThreadDelete, - /// Permissions were updated for a command - ApplicationCommandPermissionUpdate = 121, - /// Auto moderation rule was created - AutoModerationRuleCreate = 140, - /// Auto moderation rule was updated - AutoModerationRuleUpdate, - /// Auto moderation rule was deleted - AutoModerationRuleDelete, - /// Message was blocked by AutoMod according to a rule. - AutoModerationBlockMessage, - /// Message was flagged by AutoMod - AudoModerationFlagMessage, - /// Member was timed out by AutoMod - AutoModerationMemberTimedOut, - /// Creator monetization request was created - CreatorMonetizationRequestCreated = 150, - /// Creator monetization terms were accepted - CreatorMonetizationTermsAccepted, - /// Guild Onboarding Question was created - OnBoardingPromptCreate = 163, - /// Guild Onboarding Question was updated - OnBoardingPromptUpdate, - /// Guild Onboarding Question was deleted - OnBoardingPromptDelete, - /// Guild Onboarding was created - OnBoardingCreate, - /// Guild Onboarding was updated - OnBoardingUpdate, - /// Guild Server Guide was created - HomeSettingsCreate = 190, - /// Guild Server Guide was updated - HomeSettingsUpdate, - }; +/// https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-audit-log-events +pub const AuditLogEvents = enum(u4) { + /// Server settings were updated + GuildUpdate = 1, + /// Channel was created + ChannelCreate = 10, + /// Channel settings were updated + ChannelUpdate, + /// Channel was deleted + ChannelDelete, + /// Permission overwrite was added to a channel + ChannelOverwriteCreate, + /// Permission overwrite was updated for a channel + ChannelOverwriteUpdate, + /// Permission overwrite was deleted from a channel + ChannelOverwriteDelete, + /// Member was removed from server + MemberKick = 20, + /// Members were pruned from server + MemberPrune, + /// Member was banned from server + MemberBanAdd, + /// Server ban was lifted for a member + MemberBanRemove, + /// Member was updated in server + MemberUpdate, + /// Member was added or removed from a role + MemberRoleUpdate, + /// Member was moved to a different voice channel + MemberMove, + /// Member was disconnected from a voice channel + MemberDisconnect, + /// Bot user was added to server + BotAdd, + /// Role was created + RoleCreate = 30, + /// Role was edited + RoleUpdate, + /// Role was deleted + RoleDelete, + /// Server invite was created + InviteCreate = 40, + /// Server invite was updated + InviteUpdate, + /// Server invite was deleted + InviteDelete, + /// Webhook was created + WebhookCreate = 50, + /// Webhook properties or channel were updated + WebhookUpdate, + /// Webhook was deleted + WebhookDelete, + /// Emoji was created + EmojiCreate = 60, + /// Emoji name was updated + EmojiUpdate, + /// Emoji was deleted + EmojiDelete, + /// Single message was deleted + MessageDelete = 72, + /// Multiple messages were deleted + MessageBulkDelete, + /// Messaged was pinned to a channel + MessagePin, + /// Message was unpinned from a channel + MessageUnpin, + /// App was added to server + IntegrationCreate = 80, + /// App was updated (as an example, its scopes were updated) + IntegrationUpdate, + /// App was removed from server + IntegrationDelete, + /// Stage instance was created (stage channel becomes live) + StageInstanceCreate, + /// Stage instace details were updated + StageInstanceUpdate, + /// Stage instance was deleted (stage channel no longer live) + StageInstanceDelete, + /// Sticker was created + StickerCreate = 90, + /// Sticker details were updated + StickerUpdate, + /// Sticker was deleted + StickerDelete, + /// Event was created + GuildScheduledEventCreate = 100, + /// Event was updated + GuildScheduledEventUpdate, + /// Event was cancelled + GuildScheduledEventDelete, + /// Thread was created in a channel + ThreadCreate = 110, + /// Thread was updated + ThreadUpdate, + /// Thread was deleted + ThreadDelete, + /// Permissions were updated for a command + ApplicationCommandPermissionUpdate = 121, + /// Auto moderation rule was created + AutoModerationRuleCreate = 140, + /// Auto moderation rule was updated + AutoModerationRuleUpdate, + /// Auto moderation rule was deleted + AutoModerationRuleDelete, + /// Message was blocked by AutoMod according to a rule. + AutoModerationBlockMessage, + /// Message was flagged by AutoMod + AudoModerationFlagMessage, + /// Member was timed out by AutoMod + AutoModerationMemberTimedOut, + /// Creator monetization request was created + CreatorMonetizationRequestCreated = 150, + /// Creator monetization terms were accepted + CreatorMonetizationTermsAccepted, + /// Guild Onboarding Question was created + OnBoardingPromptCreate = 163, + /// Guild Onboarding Question was updated + OnBoardingPromptUpdate, + /// Guild Onboarding Question was deleted + OnBoardingPromptDelete, + /// Guild Onboarding was created + OnBoardingCreate, + /// Guild Onboarding was updated + OnBoardingUpdate, + /// Guild Server Guide was created + HomeSettingsCreate = 190, + /// Guild Server Guide was updated + HomeSettingsUpdate, +}; - pub const ScheduledEventPrivacyLevel = enum(u4) { - /// the scheduled event is only accessible to guild members - GuildOnly = 2, - }; +pub const ScheduledEventPrivacyLevel = enum(u4) { + /// the scheduled event is only accessible to guild members + GuildOnly = 2, +}; - pub const ScheduledEventEntityType = enum(u4) { - StageInstance = 1, - Voice, - External, - }; +pub const ScheduledEventEntityType = enum(u4) { + StageInstance = 1, + Voice, + External, +}; - pub const ScheduledEventStatus = enum(u4) { - Scheduled = 1, - Active, - Completed, - Canceled, - }; +pub const ScheduledEventStatus = enum(u4) { + Scheduled = 1, + Active, + Completed, + Canceled, +}; - /// https://discord.com/developers/docs/resources/invite#invite-object-target-user-types - pub const TargetTypes = enum(u4) { - Stream = 1, - EmbeddedApplication, - }; +/// https://discord.com/developers/docs/resources/invite#invite-object-target-user-types +pub const TargetTypes = enum(u4) { + Stream = 1, + EmbeddedApplication, +}; - pub const ApplicationCommandTypes = enum(u4) { - /// A text-based command that shows up when a user types `/` - ChatInput = 1, - /// A UI-based command that shows up when you right click or tap on a user - User, - /// A UI-based command that shows up when you right click or tap on a message - Message, - /// A UI-based command that represents the primary way to invoke an app's Activity - PrimaryEntryPoint, - }; +pub const ApplicationCommandTypes = enum(u4) { + /// A text-based command that shows up when a user types `/` + ChatInput = 1, + /// A UI-based command that shows up when you right click or tap on a user + User, + /// A UI-based command that shows up when you right click or tap on a message + Message, + /// A UI-based command that represents the primary way to invoke an app's Activity + PrimaryEntryPoint, +}; - pub const ApplicationCommandPermissionTypes = enum(u4) { - Role = 1, - User, - Channel, - }; +pub const ApplicationCommandPermissionTypes = enum(u4) { + Role = 1, + User, + Channel, +}; - /// https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags - /// Permissions v2 - pub const BitwisePermissionFlags = packed struct { - pub fn toRaw(self: BitwisePermissionFlags) u64 { - return @bitCast(self); - } +/// https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags +/// Permissions v2 +pub const BitwisePermissionFlags = packed struct { + pub fn toRaw(self: BitwisePermissionFlags) u64 { + return @bitCast(self); + } - pub fn fromRaw(raw: u64) BitwisePermissionFlags { - return @bitCast(raw); - } + pub fn fromRaw(raw: u64) BitwisePermissionFlags { + return @bitCast(raw); + } pub fn jsonParse(allocator: std.mem.Allocator, src: anytype, _: std.json.ParseOptions) !@This() { const value = try std.json.innerParse(std.json.Value, allocator, src, .{ @@ -1097,569 +1097,394 @@ pub const GuildFeatures = enum { } - /// Allows creation of instant invites - CREATE_INSTANT_INVITE: bool = false, - /// Allows kicking members - KICK_MEMBERS: bool = false, - /// Allows banning members - BAN_MEMBERS: bool = false, - /// Allows all permissions and bypasses channel permission overwrites - ADMINISTRATOR: bool = false, - /// Allows management and editing of channels - MANAGE_CHANNELS: bool = false, - /// Allows management and editing of the guild - MANAGE_GUILD: bool = false, - /// Allows for the addition of reactions to messages - ADD_REACTIONS: bool = false, - /// Allows for viewing of audit logs - VIEW_AUDIT_LOG: bool = false, - /// Allows for using priority speaker in a voice channel - PRIORITY_SPEAKER: bool = false, - /// Allows the user to go live - STREAM: bool = false, - /// Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels - VIEW_CHANNEL: bool = false, - /// Allows for sending messages in a channel. (does not allow sending messages in threads) - SEND_MESSAGES: bool = false, - /// Allows for sending of /tts messages - SEND_TTS_MESSAGES: bool = false, - /// Allows for deletion of other users messages - MANAGE_MESSAGES: bool = false, - /// Links sent by users with this permission will be auto-embedded - EMBED_LINKS: bool = false, - /// Allows for uploading images and files - ATTACH_FILES: bool = false, - /// Allows for reading of message history - READ_MESSAGE_HISTORY: bool = false, - /// Allows for using the \@everyone tag to notify all users in a channel, and the \@here tag to notify all online users in a channel - MENTION_EVERYONE: bool = false, - /// Allows the usage of custom emojis from other servers - USE_EXTERNAL_EMOJIS: bool = false, - /// Allows for viewing guild insights - VIEW_GUILD_INSIGHTS: bool = false, - /// Allows for joining of a voice channel - CONNECT: bool = false, - /// Allows for speaking in a voice channel - SPEAK: bool = false, - /// Allows for muting members in a voice channel - MUTE_MEMBERS: bool = false, - /// Allows for deafening of members in a voice channel - DEAFEN_MEMBERS: bool = false, - /// Allows for moving of members between voice channels - MOVE_MEMBERS: bool = false, - /// Allows for using voice-activity-detection in a voice channel - USE_VAD: bool = false, - /// Allows for modification of own nickname - CHANGE_NICKNAME: bool = false, - /// Allows for modification of other users nicknames - MANAGE_NICKNAMES: bool = false, - /// Allows management and editing of roles - MANAGE_ROLES: bool = false, - /// Allows management and editing of webhooks - MANAGE_WEBHOOKS: bool = false, - /// Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users - MANAGE_GUILD_EXPRESSIONS: bool = false, - /// Allows members to use application commands in text channels - USE_SLASH_COMMANDS: bool = false, - /// Allows for requesting to speak in stage channels. - REQUEST_TO_SPEAK: bool = false, - /// Allows for editing and deleting scheduled events created by all users - MANAGE_EVENTS: bool = false, - /// Allows for deleting and archiving threads, and viewing all private threads - MANAGE_THREADS: bool = false, - /// Allows for creating public and announcement threads - CREATE_PUBLIC_THREADS: bool = false, - /// Allows for creating private threads - CREATE_PRIVATE_THREADS: bool = false, - /// Allows the usage of custom stickers from other servers - USE_EXTERNAL_STICKERS: bool = false, - /// Allows for sending messages in threads - SEND_MESSAGES_IN_THREADS: bool = false, - /// Allows for launching activities (applications with the `EMBEDDED` flag) in a voice channel. - USE_EMBEDDED_ACTIVITIES: bool = false, - /// Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels - MODERATE_MEMBERS: bool = false, - /// Allows for viewing role subscription insights. - VIEW_CREATOR_MONETIZATION_ANALYTICS: bool = false, - /// Allows for using soundboard in a voice channel. - USE_SOUNDBOARD: bool = false, - /// Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user - CREATE_GUILD_EXPRESSIONS: bool = false, - /// Allows for creating scheduled events, and editing and deleting those created by the current user - CREATE_EVENTS: bool = false, - /// Allows the usage of custom soundboards sounds from other servers - USE_EXTERNAL_SOUNDS: bool = false, - /// Allows sending voice messages - SEND_VOICE_MESSAGES: bool = false, - /// Allows sending polls - SEND_POLLS: bool = false, - /// Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps but the responses will be ephemeral. This only applies to apps not also installed to the server. - USE_EXTERNAL_APPS: bool = false, - _pad: u15 = 0, - }; + /// Allows creation of instant invites + CREATE_INSTANT_INVITE: bool = false, + /// Allows kicking members + KICK_MEMBERS: bool = false, + /// Allows banning members + BAN_MEMBERS: bool = false, + /// Allows all permissions and bypasses channel permission overwrites + ADMINISTRATOR: bool = false, + /// Allows management and editing of channels + MANAGE_CHANNELS: bool = false, + /// Allows management and editing of the guild + MANAGE_GUILD: bool = false, + /// Allows for the addition of reactions to messages + ADD_REACTIONS: bool = false, + /// Allows for viewing of audit logs + VIEW_AUDIT_LOG: bool = false, + /// Allows for using priority speaker in a voice channel + PRIORITY_SPEAKER: bool = false, + /// Allows the user to go live + STREAM: bool = false, + /// Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels + VIEW_CHANNEL: bool = false, + /// Allows for sending messages in a channel. (does not allow sending messages in threads) + SEND_MESSAGES: bool = false, + /// Allows for sending of /tts messages + SEND_TTS_MESSAGES: bool = false, + /// Allows for deletion of other users messages + MANAGE_MESSAGES: bool = false, + /// Links sent by users with this permission will be auto-embedded + EMBED_LINKS: bool = false, + /// Allows for uploading images and files + ATTACH_FILES: bool = false, + /// Allows for reading of message history + READ_MESSAGE_HISTORY: bool = false, + /// Allows for using the \@everyone tag to notify all users in a channel, and the \@here tag to notify all online users in a channel + MENTION_EVERYONE: bool = false, + /// Allows the usage of custom emojis from other servers + USE_EXTERNAL_EMOJIS: bool = false, + /// Allows for viewing guild insights + VIEW_GUILD_INSIGHTS: bool = false, + /// Allows for joining of a voice channel + CONNECT: bool = false, + /// Allows for speaking in a voice channel + SPEAK: bool = false, + /// Allows for muting members in a voice channel + MUTE_MEMBERS: bool = false, + /// Allows for deafening of members in a voice channel + DEAFEN_MEMBERS: bool = false, + /// Allows for moving of members between voice channels + MOVE_MEMBERS: bool = false, + /// Allows for using voice-activity-detection in a voice channel + USE_VAD: bool = false, + /// Allows for modification of own nickname + CHANGE_NICKNAME: bool = false, + /// Allows for modification of other users nicknames + MANAGE_NICKNAMES: bool = false, + /// Allows management and editing of roles + MANAGE_ROLES: bool = false, + /// Allows management and editing of webhooks + MANAGE_WEBHOOKS: bool = false, + /// Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users + MANAGE_GUILD_EXPRESSIONS: bool = false, + /// Allows members to use application commands in text channels + USE_SLASH_COMMANDS: bool = false, + /// Allows for requesting to speak in stage channels. + REQUEST_TO_SPEAK: bool = false, + /// Allows for editing and deleting scheduled events created by all users + MANAGE_EVENTS: bool = false, + /// Allows for deleting and archiving threads, and viewing all private threads + MANAGE_THREADS: bool = false, + /// Allows for creating public and announcement threads + CREATE_PUBLIC_THREADS: bool = false, + /// Allows for creating private threads + CREATE_PRIVATE_THREADS: bool = false, + /// Allows the usage of custom stickers from other servers + USE_EXTERNAL_STICKERS: bool = false, + /// Allows for sending messages in threads + SEND_MESSAGES_IN_THREADS: bool = false, + /// Allows for launching activities (applications with the `EMBEDDED` flag) in a voice channel. + USE_EMBEDDED_ACTIVITIES: bool = false, + /// Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels + MODERATE_MEMBERS: bool = false, + /// Allows for viewing role subscription insights. + VIEW_CREATOR_MONETIZATION_ANALYTICS: bool = false, + /// Allows for using soundboard in a voice channel. + USE_SOUNDBOARD: bool = false, + /// Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user + CREATE_GUILD_EXPRESSIONS: bool = false, + /// Allows for creating scheduled events, and editing and deleting those created by the current user + CREATE_EVENTS: bool = false, + /// Allows the usage of custom soundboards sounds from other servers + USE_EXTERNAL_SOUNDS: bool = false, + /// Allows sending voice messages + SEND_VOICE_MESSAGES: bool = false, + /// Allows sending polls + SEND_POLLS: bool = false, + /// Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps but the responses will be ephemeral. This only applies to apps not also installed to the server. + USE_EXTERNAL_APPS: bool = false, + _pad: u15 = 0, +}; - pub const PermissionStrings = union(enum) { - /// Allows creation of instant invites - CREATE_INSTANT_INVITE, - /// Allows kicking members - KICK_MEMBERS, - /// Allows banning members - BAN_MEMBERS, - /// Allows all permissions and bypasses channel permission overwrites - ADMINISTRATOR, - /// Allows management and editing of channels - MANAGE_CHANNELS, - /// Allows management and editing of the guild - MANAGE_GUILD, - /// Allows for the addition of reactions to messages - ADD_REACTIONS, - /// Allows for viewing of audit logs - VIEW_AUDIT_LOG, - /// Allows for using priority speaker in a voice channel - PRIORITY_SPEAKER, - /// Allows the user to go live - STREAM, - /// Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels - VIEW_CHANNEL, - /// Allows for sending messages in a channel. (does not allow sending messages in threads) - SEND_MESSAGES, - /// Allows for sending of /tts messages - SEND_TTS_MESSAGES, - /// Allows for deletion of other users messages - MANAGE_MESSAGES, - /// Links sent by users with this permission will be auto-embedded - EMBED_LINKS, - /// Allows for uploading images and files - ATTACH_FILES, - /// Allows for reading of message history - READ_MESSAGE_HISTORY, - /// Allows for using the \@everyone tag to notify all users in a channel, and the \@here tag to notify all online users in a channel - MENTION_EVERYONE, - /// Allows the usage of custom emojis from other servers - USE_EXTERNAL_EMOJIS, - /// Allows for viewing guild insights - VIEW_GUILD_INSIGHTS, - /// Allows for joining of a voice channel - CONNECT, - /// Allows for speaking in a voice channel - SPEAK, - /// Allows for muting members in a voice channel - MUTE_MEMBERS, - /// Allows for deafening of members in a voice channel - DEAFEN_MEMBERS, - /// Allows for moving of members between voice channels - MOVE_MEMBERS, - /// Allows for using voice-activity-detection in a voice channel - USE_VAD, - /// Allows for modification of own nickname - CHANGE_NICKNAME, - /// Allows for modification of other users nicknames - MANAGE_NICKNAMES, - /// Allows management and editing of roles - MANAGE_ROLES, - /// Allows management and editing of webhooks - MANAGE_WEBHOOKS, - /// Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users - MANAGE_GUILD_EXPRESSIONS, - /// Allows members to use application commands in text channels - USE_SLASH_COMMANDS, - /// Allows for requesting to speak in stage channels. - REQUEST_TO_SPEAK, - /// Allows for editing and deleting scheduled events created by all users - MANAGE_EVENTS, - /// Allows for deleting and archiving threads, and viewing all private threads - MANAGE_THREADS, - /// Allows for creating public and announcement threads - CREATE_PUBLIC_THREADS, - /// Allows for creating private threads - CREATE_PRIVATE_THREADS, - /// Allows the usage of custom stickers from other servers - USE_EXTERNAL_STICKERS, - /// Allows for sending messages in threads - SEND_MESSAGES_IN_THREADS, - /// Allows for launching activities (applications with the `EMBEDDED` flag) in a voice channel. - USE_EMBEDDED_ACTIVITIES, - /// Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels - MODERATE_MEMBERS, - /// Allows for viewing role subscription insights. - VIEW_CREATOR_MONETIZATION_ANALYTICS, - /// Allows for using soundboard in a voice channel. - USE_SOUNDBOARD, - /// Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user - CREATE_GUILD_EXPRESSIONS, - /// Allows for creating scheduled events, and editing and deleting those created by the current user - CREATE_EVENTS, - /// Allows the usage of custom soundboards sounds from other servers - USE_EXTERNAL_SOUNDS, - /// Allows sending voice messages - SEND_VOICE_MESSAGES, - /// Allows sending polls - SEND_POLLS, - /// Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps but the responses will be ephemeral. This only applies to apps not also installed to the server. - USE_EXTERNAL_APPS, - }; +pub const PermissionStrings = union(enum) { + /// Allows creation of instant invites + CREATE_INSTANT_INVITE, + /// Allows kicking members + KICK_MEMBERS, + /// Allows banning members + BAN_MEMBERS, + /// Allows all permissions and bypasses channel permission overwrites + ADMINISTRATOR, + /// Allows management and editing of channels + MANAGE_CHANNELS, + /// Allows management and editing of the guild + MANAGE_GUILD, + /// Allows for the addition of reactions to messages + ADD_REACTIONS, + /// Allows for viewing of audit logs + VIEW_AUDIT_LOG, + /// Allows for using priority speaker in a voice channel + PRIORITY_SPEAKER, + /// Allows the user to go live + STREAM, + /// Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels + VIEW_CHANNEL, + /// Allows for sending messages in a channel. (does not allow sending messages in threads) + SEND_MESSAGES, + /// Allows for sending of /tts messages + SEND_TTS_MESSAGES, + /// Allows for deletion of other users messages + MANAGE_MESSAGES, + /// Links sent by users with this permission will be auto-embedded + EMBED_LINKS, + /// Allows for uploading images and files + ATTACH_FILES, + /// Allows for reading of message history + READ_MESSAGE_HISTORY, + /// Allows for using the \@everyone tag to notify all users in a channel, and the \@here tag to notify all online users in a channel + MENTION_EVERYONE, + /// Allows the usage of custom emojis from other servers + USE_EXTERNAL_EMOJIS, + /// Allows for viewing guild insights + VIEW_GUILD_INSIGHTS, + /// Allows for joining of a voice channel + CONNECT, + /// Allows for speaking in a voice channel + SPEAK, + /// Allows for muting members in a voice channel + MUTE_MEMBERS, + /// Allows for deafening of members in a voice channel + DEAFEN_MEMBERS, + /// Allows for moving of members between voice channels + MOVE_MEMBERS, + /// Allows for using voice-activity-detection in a voice channel + USE_VAD, + /// Allows for modification of own nickname + CHANGE_NICKNAME, + /// Allows for modification of other users nicknames + MANAGE_NICKNAMES, + /// Allows management and editing of roles + MANAGE_ROLES, + /// Allows management and editing of webhooks + MANAGE_WEBHOOKS, + /// Allows for editing and deleting emojis, stickers, and soundboard sounds created by all users + MANAGE_GUILD_EXPRESSIONS, + /// Allows members to use application commands in text channels + USE_SLASH_COMMANDS, + /// Allows for requesting to speak in stage channels. + REQUEST_TO_SPEAK, + /// Allows for editing and deleting scheduled events created by all users + MANAGE_EVENTS, + /// Allows for deleting and archiving threads, and viewing all private threads + MANAGE_THREADS, + /// Allows for creating public and announcement threads + CREATE_PUBLIC_THREADS, + /// Allows for creating private threads + CREATE_PRIVATE_THREADS, + /// Allows the usage of custom stickers from other servers + USE_EXTERNAL_STICKERS, + /// Allows for sending messages in threads + SEND_MESSAGES_IN_THREADS, + /// Allows for launching activities (applications with the `EMBEDDED` flag) in a voice channel. + USE_EMBEDDED_ACTIVITIES, + /// Allows for timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels + MODERATE_MEMBERS, + /// Allows for viewing role subscription insights. + VIEW_CREATOR_MONETIZATION_ANALYTICS, + /// Allows for using soundboard in a voice channel. + USE_SOUNDBOARD, + /// Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user + CREATE_GUILD_EXPRESSIONS, + /// Allows for creating scheduled events, and editing and deleting those created by the current user + CREATE_EVENTS, + /// Allows the usage of custom soundboards sounds from other servers + USE_EXTERNAL_SOUNDS, + /// Allows sending voice messages + SEND_VOICE_MESSAGES, + /// Allows sending polls + SEND_POLLS, + /// Allows user-installed apps to send public responses. When disabled, users will still be allowed to use their apps but the responses will be ephemeral. This only applies to apps not also installed to the server. + USE_EXTERNAL_APPS, +}; - /// https://discord.com/developers/docs/topics/opcodes-and-status-codes#opcodes-and-status-codes - pub const GatewayCloseEventCodes = enum(u16) { - /// A normal closure of the gateway. You may attempt to reconnect. - NormalClosure = 1000, - /// We're not sure what went wrong. Try reconnecting? - UnknownError = 4000, - /// You sent an invalid [Gateway opcode](https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes) or an invalid payload for an opcode. Don't do that! - UnknownOpcode, - /// You sent an invalid [payload](https://discord.com/developers/docs/topics/gateway#sending-payloads) to us. Don't do that! - DecodeError, - /// You sent us a payload prior to [identifying](https://discord.com/developers/docs/topics/gateway-events#identify), or this session has been invalidated. - NotAuthenticated, - /// The account token sent with your [identify payload](https://discord.com/developers/docs/topics/gateway-events#identify) is incorrect. - AuthenticationFailed, - /// You sent more than one identify payload. Don't do that! - AlreadyAuthenticated, - /// The sequence sent when [resuming](https://discord.com/developers/docs/topics/gateway-events#resume) the session was invalid. Reconnect and start a new session. - InvalidSeq = 4007, - /// Woah nelly! You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this. - RateLimited, - /// Your session timed out. Reconnect and start a new one. - SessionTimedOut, - /// You sent us an invalid [shard when identifying](https://discord.com/developers/docs/topics/gateway#sharding). - InvalidShard, - /// The session would have handled too many guilds - you are required to [shard](https://discord.com/developers/docs/topics/gateway#sharding) your connection in order to connect. - ShardingRequired, - /// You sent an invalid version for the gateway. - InvalidApiVersion, - /// You sent an invalid intent for a [Gateway Intent](https://discord.com/developers/docs/topics/gateway#gateway-intents). You may have incorrectly calculated the bitwise value. - InvalidIntents, - /// You sent a disallowed intent for a [Gateway Intent](https://discord.com/developers/docs/topics/gateway#gateway-intents). You may have tried to specify an intent that you [have not enabled or are not approved for](https://discord.com/developers/docs/topics/gateway#privileged-intents). - DisallowedIntents, - }; +/// https://discord.com/developers/docs/topics/opcodes-and-status-codes#opcodes-and-status-codes +pub const GatewayCloseEventCodes = enum(u16) { + /// A normal closure of the gateway. You may attempt to reconnect. + NormalClosure = 1000, + /// We're not sure what went wrong. Try reconnecting? + UnknownError = 4000, + /// You sent an invalid [Gateway opcode](https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes) or an invalid payload for an opcode. Don't do that! + UnknownOpcode, + /// You sent an invalid [payload](https://discord.com/developers/docs/topics/gateway#sending-payloads) to us. Don't do that! + DecodeError, + /// You sent us a payload prior to [identifying](https://discord.com/developers/docs/topics/gateway-events#identify), or this session has been invalidated. + NotAuthenticated, + /// The account token sent with your [identify payload](https://discord.com/developers/docs/topics/gateway-events#identify) is incorrect. + AuthenticationFailed, + /// You sent more than one identify payload. Don't do that! + AlreadyAuthenticated, + /// The sequence sent when [resuming](https://discord.com/developers/docs/topics/gateway-events#resume) the session was invalid. Reconnect and start a new session. + InvalidSeq = 4007, + /// Woah nelly! You're sending payloads to us too quickly. Slow it down! You will be disconnected on receiving this. + RateLimited, + /// Your session timed out. Reconnect and start a new one. + SessionTimedOut, + /// You sent us an invalid [shard when identifying](https://discord.com/developers/docs/topics/gateway#sharding). + InvalidShard, + /// The session would have handled too many guilds - you are required to [shard](https://discord.com/developers/docs/topics/gateway#sharding) your connection in order to connect. + ShardingRequired, + /// You sent an invalid version for the gateway. + InvalidApiVersion, + /// You sent an invalid intent for a [Gateway Intent](https://discord.com/developers/docs/topics/gateway#gateway-intents). You may have incorrectly calculated the bitwise value. + InvalidIntents, + /// You sent a disallowed intent for a [Gateway Intent](https://discord.com/developers/docs/topics/gateway#gateway-intents). You may have tried to specify an intent that you [have not enabled or are not approved for](https://discord.com/developers/docs/topics/gateway#privileged-intents). + DisallowedIntents, +}; - /// https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes - pub const GatewayOpcodes = enum(u4) { - /// An event was dispatched. - Dispatch, - /// Fired periodically by the client to keep the connection alive. - Heartbeat, - /// Starts a new session during the initial handshake. - Identify, - /// Update the client's presence. - PresenceUpdate, - /// Used to join/leave or move between voice channels. - VoiceStateUpdate, - /// Resume a previous session that was disconnected. - Resume = 6, - /// You should attempt to reconnect and resume immediately. - Reconnect, - /// Request information about offline guild members in a large guild. - RequestGuildMembers, - /// The session has been invalidated. You should reconnect and identify/resume accordingly. - InvalidSession, - /// Sent immediately after connecting, contains the `heartbeat_interval` to use. - Hello, - /// Sent in response to receiving a heartbeat to acknowledge that it has been received. - HeartbeatACK, - }; +/// https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes +pub const GatewayOpcodes = enum(u4) { + /// An event was dispatched. + Dispatch, + /// Fired periodically by the client to keep the connection alive. + Heartbeat, + /// Starts a new session during the initial handshake. + Identify, + /// Update the client's presence. + PresenceUpdate, + /// Used to join/leave or move between voice channels. + VoiceStateUpdate, + /// Resume a previous session that was disconnected. + Resume = 6, + /// You should attempt to reconnect and resume immediately. + Reconnect, + /// Request information about offline guild members in a large guild. + RequestGuildMembers, + /// The session has been invalidated. You should reconnect and identify/resume accordingly. + InvalidSession, + /// Sent immediately after connecting, contains the `heartbeat_interval` to use. + Hello, + /// Sent in response to receiving a heartbeat to acknowledge that it has been received. + HeartbeatACK, +}; - pub const GatewayDispatchEventNames = union(enum) { - APPLICATION_COMMAND_PERMISSIONS_UPDATE, - AUTO_MODERATION_RULE_CREATE, - AUTO_MODERATION_RULE_UPDATE, - AUTO_MODERATION_RULE_DELETE, - AUTO_MODERATION_ACTION_EXECUTION, - CHANNEL_CREATE, - CHANNEL_UPDATE, - CHANNEL_DELETE, - CHANNEL_PINS_UPDATE, - THREAD_CREATE, - THREAD_UPDATE, - THREAD_DELETE, - THREAD_LIST_SYNC, - THREAD_MEMBER_UPDATE, - THREAD_MEMBERS_UPDATE, - GUILD_AUDIT_LOG_ENTRY_CREATE, - GUILD_CREATE, - GUILD_UPDATE, - GUILD_DELETE, - GUILD_BAN_ADD, - GUILD_BAN_REMOVE, - GUILD_EMOJIS_UPDATE, - GUILD_STICKERS_UPDATE, - GUILD_INTEGRATIONS_UPDATE, - GUILD_MEMBER_ADD, - GUILD_MEMBER_REMOVE, - GUILD_MEMBER_UPDATE, - GUILD_MEMBERS_CHUNK, - GUILD_ROLE_CREATE, - GUILD_ROLE_UPDATE, - GUILD_ROLE_DELETE, - GUILD_SCHEDULED_EVENT_CREATE, - GUILD_SCHEDULED_EVENT_UPDATE, - GUILD_SCHEDULED_EVENT_DELETE, - GUILD_SCHEDULED_EVENT_USER_ADD, - GUILD_SCHEDULED_EVENT_USER_REMOVE, - INTEGRATION_CREATE, - INTEGRATION_UPDATE, - INTEGRATION_DELETE, - INTERACTION_CREATE, - INVITE_CREATE, - INVITE_DELETE, - MESSAGE_CREATE, - MESSAGE_UPDATE, - MESSAGE_DELETE, - MESSAGE_DELETE_BULK, - MESSAGE_REACTION_ADD, - MESSAGE_REACTION_REMOVE, - MESSAGE_REACTION_REMOVE_ALL, - MESSAGE_REACTION_REMOVE_EMOJI, - PRESENCE_UPDATE, - STAGE_INSTANCE_CREATE, - STAGE_INSTANCE_UPDATE, - STAGE_INSTANCE_DELETE, - TYPING_START, - USER_UPDATE, - VOICE_CHANNEL_EFFECT_SEND, - VOICE_STATE_UPDATE, - VOICE_SERVER_UPDATE, - WEBHOOKS_UPDATE, - ENTITLEMENT_CREATE, - ENTITLEMENT_UPDATE, - ENTITLEMENT_DELETE, - MESSAGE_POLL_VOTE_ADD, - MESSAGE_POLL_VOTE_REMOVE, +pub const GatewayDispatchEventNames = union(enum) { + APPLICATION_COMMAND_PERMISSIONS_UPDATE, + AUTO_MODERATION_RULE_CREATE, + AUTO_MODERATION_RULE_UPDATE, + AUTO_MODERATION_RULE_DELETE, + AUTO_MODERATION_ACTION_EXECUTION, + CHANNEL_CREATE, + CHANNEL_UPDATE, + CHANNEL_DELETE, + CHANNEL_PINS_UPDATE, + THREAD_CREATE, + THREAD_UPDATE, + THREAD_DELETE, + THREAD_LIST_SYNC, + THREAD_MEMBER_UPDATE, + THREAD_MEMBERS_UPDATE, + GUILD_AUDIT_LOG_ENTRY_CREATE, + GUILD_CREATE, + GUILD_UPDATE, + GUILD_DELETE, + GUILD_BAN_ADD, + GUILD_BAN_REMOVE, + GUILD_EMOJIS_UPDATE, + GUILD_STICKERS_UPDATE, + GUILD_INTEGRATIONS_UPDATE, + GUILD_MEMBER_ADD, + GUILD_MEMBER_REMOVE, + GUILD_MEMBER_UPDATE, + GUILD_MEMBERS_CHUNK, + GUILD_ROLE_CREATE, + GUILD_ROLE_UPDATE, + GUILD_ROLE_DELETE, + GUILD_SCHEDULED_EVENT_CREATE, + GUILD_SCHEDULED_EVENT_UPDATE, + GUILD_SCHEDULED_EVENT_DELETE, + GUILD_SCHEDULED_EVENT_USER_ADD, + GUILD_SCHEDULED_EVENT_USER_REMOVE, + INTEGRATION_CREATE, + INTEGRATION_UPDATE, + INTEGRATION_DELETE, + INTERACTION_CREATE, + INVITE_CREATE, + INVITE_DELETE, + MESSAGE_CREATE, + MESSAGE_UPDATE, + MESSAGE_DELETE, + MESSAGE_DELETE_BULK, + MESSAGE_REACTION_ADD, + MESSAGE_REACTION_REMOVE, + MESSAGE_REACTION_REMOVE_ALL, + MESSAGE_REACTION_REMOVE_EMOJI, + PRESENCE_UPDATE, + STAGE_INSTANCE_CREATE, + STAGE_INSTANCE_UPDATE, + STAGE_INSTANCE_DELETE, + TYPING_START, + USER_UPDATE, + VOICE_CHANNEL_EFFECT_SEND, + VOICE_STATE_UPDATE, + VOICE_SERVER_UPDATE, + WEBHOOKS_UPDATE, + ENTITLEMENT_CREATE, + ENTITLEMENT_UPDATE, + ENTITLEMENT_DELETE, + MESSAGE_POLL_VOTE_ADD, + MESSAGE_POLL_VOTE_REMOVE, - READY, - RESUMED, - }; - - /// https://discord.com/developers/docs/topics/gateway#list-of-intents - pub const GatewayIntents = packed struct { - pub fn toRaw(self: GatewayIntents) u32 { - return @bitCast(self); - } - - pub fn fromRaw(raw: u32) GatewayIntents { - return @bitCast(raw); - } - - pub fn jsonParse(allocator: std.mem.Allocator, src: anytype, _: std.json.ParseOptions) !@This() { - const value = try std.json.innerParse(std.json.Value, allocator, src, .{ - .ignore_unknown_fields = true, - .max_value_len = 0x1000, - }); - if (value != .integer) @panic("Invalid value for bitfield"); - - return fromRaw(@intCast(value.integer)); - } - - pub fn jsonParseFromValue(_: std.mem.Allocator, src: std.json.Value, _: std.json.ParseOptions) @This() { - if (src != .integer) @panic("Invalid value for bitfield"); - return fromRaw(@intCast(src.integer)); - } + READY, + RESUMED, +}; - /// - /// - GUILD_CREATE - /// - GUILD_UPDATE - /// - GUILD_DELETE - /// - GUILD_ROLE_CREATE - /// - GUILD_ROLE_UPDATE - /// - GUILD_ROLE_DELETE - /// - CHANNEL_CREATE - /// - CHANNEL_UPDATE - /// - CHANNEL_DELETE - /// - CHANNEL_PINS_UPDATE - /// - THREAD_CREATE - /// - THREAD_UPDATE - /// - THREAD_DELETE - /// - THREAD_LIST_SYNC - /// - THREAD_MEMBER_UPDATE - /// - THREAD_MEMBERS_UPDATE - /// - STAGE_INSTANCE_CREATE - /// - STAGE_INSTANCE_UPDATE - /// - STAGE_INSTANCE_DELETE - //// - Guilds: bool = false, - /// - /// - GUILD_MEMBER_ADD - /// - GUILD_MEMBER_UPDATE - /// - GUILD_MEMBER_REMOVE - /// - THREAD_MEMBERS_UPDATE - /// - /// This is a privileged intent. - //// - GuildMembers: bool = false, - /// - /// - GUILD_AUDIT_LOG_ENTRY_CREATE - /// - GUILD_BAN_ADD - /// - GUILD_BAN_REMOVE - //// - GuildModeration: bool = false, - /// - /// - GUILD_EMOJIS_UPDATE - /// - GUILD_STICKERS_UPDATE - //// - GuildEmojisAndStickers: bool = false, - /// - /// - GUILD_INTEGRATIONS_UPDATE - /// - INTEGRATION_CREATE - /// - INTEGRATION_UPDATE - /// - INTEGRATION_DELETE - //// - GuildIntegrations: bool = false, - /// - /// - WEBHOOKS_UPDATE - //// - GuildWebhooks: bool = false, - /// - /// - INVITE_CREATE - /// - INVITE_DELETE - //// - GuildInvites: bool = false, - /// - /// - VOICE_STATE_UPDATE - /// - VOICE_CHANNEL_EFFECT_SEND - //// - GuildVoiceStates: bool = false, - /// - /// - PRESENCE_UPDATE - /// - /// This is a privileged intent. - //// - GuildPresences: bool = false, - /// - /// - MESSAGE_CREATE - /// - MESSAGE_UPDATE - /// - MESSAGE_DELETE - /// - MESSAGE_DELETE_BULK - /// - /// The messages do not contain content by default. - /// If you want to receive their content too, you need to turn on the privileged `MESSAGE_CONTENT` intent. */ - GuildMessages: bool = false, - /// - /// - MESSAGE_REACTION_ADD - /// - MESSAGE_REACTION_REMOVE - /// - MESSAGE_REACTION_REMOVE_ALL - /// - MESSAGE_REACTION_REMOVE_EMOJI - //// - GuildMessageReactions: bool = false, - /// - /// - TYPING_START - //// - GuildMessageTyping: bool = false, - /// - /// - CHANNEL_CREATE - /// - MESSAGE_CREATE - /// - MESSAGE_UPDATE - /// - MESSAGE_DELETE - /// - CHANNEL_PINS_UPDATE - //// - DirectMessages: bool = false, - /// - /// - MESSAGE_REACTION_ADD - /// - MESSAGE_REACTION_REMOVE - /// - MESSAGE_REACTION_REMOVE_ALL - /// - MESSAGE_REACTION_REMOVE_EMOJI - //// - DirectMessageReactions: bool = false, - /// - /// - TYPING_START - //// - DirectMessageTyping: bool = false, - /// - /// This intent will add all content related values to message events. - /// - /// This is a privileged intent. - //// - MessageContent: bool = false, - /// - /// - GUILD_SCHEDULED_EVENT_CREATE - /// - GUILD_SCHEDULED_EVENT_UPDATE - /// - GUILD_SCHEDULED_EVENT_DELETE - /// - GUILD_SCHEDULED_EVENT_USER_ADD this is experimental and unstable. - /// - GUILD_SCHEDULED_EVENT_USER_REMOVE this is experimental and unstable. - //// - GuildScheduledEvents: bool = false, - _pad: u4 = 0, - /// - /// - AUTO_MODERATION_RULE_CREATE - /// - AUTO_MODERATION_RULE_UPDATE - /// - AUTO_MODERATION_RULE_DELETE - //// - AutoModerationConfiguration: bool = false, - /// - /// - AUTO_MODERATION_ACTION_EXECUTION - //// - AutoModerationExecution: bool = false, - _pad2: u3 = 0, - /// - /// - MESSAGE_POLL_VOTE_ADD - /// - MESSAGE_POLL_VOTE_REMOVE - //// - GuildMessagePolls: bool = false, - /// - /// - MESSAGE_POLL_VOTE_ADD - /// - MESSAGE_POLL_VOTE_REMOVE - //// - DirectMessagePolls: bool = false, - _pad3: u4 = 0, - }; +/// https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionresponsetype +pub const InteractionResponseTypes = enum(u4) { + /// ACK a `Ping` + Pong = 1, + /// Respond to an interaction with a message + ChannelMessageWithSource = 4, + /// ACK an interaction and edit a response later, the user sees a loading state + DeferredChannelMessageWithSource = 5, + /// For components, ACK an interaction and edit the original message later; the user does not see a loading state + DeferredUpdateMessage = 6, + /// For components, edit the message the component was attached to + UpdateMessage = 7, + /// For Application Command Options, send an autocomplete result + ApplicationCommandAutocompleteResult = 8, + /// For Command or Component interactions, send a Modal response + Modal = 9, + /// + /// Respond to an interaction with an upgrade button, only available for apps with monetization enabled + /// + /// @deprecated You should migrate to the premium button components + PremiumRequired = 10, + /// + /// Launch the Activity associated with the app. + /// + /// @remarks + /// Only available for apps with Activities enabled + LaunchActivity = 12, +}; - /// https://discord.com/developers/docs/topics/gateway#list-of-intents - pub const Intents = GatewayIntents; +pub const SortOrderTypes = enum { + /// Sort forum posts by activity + LatestActivity, + /// Sort forum posts by creation time (from most recent to oldest) + CreationDate, +}; - /// https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionresponsetype - pub const InteractionResponseTypes = enum(u4) { - /// ACK a `Ping` - Pong = 1, - /// Respond to an interaction with a message - ChannelMessageWithSource = 4, - /// ACK an interaction and edit a response later, the user sees a loading state - DeferredChannelMessageWithSource = 5, - /// For components, ACK an interaction and edit the original message later; the user does not see a loading state - DeferredUpdateMessage = 6, - /// For components, edit the message the component was attached to - UpdateMessage = 7, - /// For Application Command Options, send an autocomplete result - ApplicationCommandAutocompleteResult = 8, - /// For Command or Component interactions, send a Modal response - Modal = 9, - /// - /// Respond to an interaction with an upgrade button, only available for apps with monetization enabled - /// - /// @deprecated You should migrate to the premium button components - PremiumRequired = 10, - /// - /// Launch the Activity associated with the app. - /// - /// @remarks - /// Only available for apps with Activities enabled - LaunchActivity = 12, - }; +pub const ForumLayout = enum { + /// No default has been set for forum channel. + NotSet, + /// Display posts as a list. + ListView, + /// Display posts as a collection of tiles. + GalleryView, +}; - pub const SortOrderTypes = enum { - /// Sort forum posts by activity - LatestActivity, - /// Sort forum posts by creation time (from most recent to oldest) - CreationDate, - }; - - pub const ForumLayout = enum { - /// No default has been set for forum channel. - NotSet, - /// Display posts as a list. - ListView, - /// Display posts as a collection of tiles. - GalleryView, - }; - - /// https://discord.com/developers/docs/reference#image-formatting - /// json is only for stickers - pub const ImageFormat = union(enum) { - jpg, - jpeg, - png, - webp, - gif, - json, +/// https://discord.com/developers/docs/reference#image-formatting +/// json is only for stickers +pub const ImageFormat = union(enum) { + jpg, + jpeg, + png, + webp, + gif, + json, }; /// https://discord.com/developers/docs/reference#image-formatting diff --git a/src/structures/types.zig b/src/structures/types.zig index 5e2ab5b..494a3f4 100644 --- a/src/structures/types.zig +++ b/src/structures/types.zig @@ -66,8 +66,6 @@ pub const GatewayCloseEventCodes = @import("shared.zig").GatewayCloseEventCodes; pub const GatewayOpcodes = @import("shared.zig").GatewayOpcodes; pub const GatewayDispatchEventNames = @import("shared.zig").GatewayDispatchEventNames; - pub const GatewayIntents = @import("shared.zig").GatewayIntents; - pub const Intents = @import("shared.zig").Intents; pub const InteractionResponseTypes = @import("shared.zig").InteractionResponseTypes; pub const SortOrderTypes = @import("shared.zig").SortOrderTypes; pub const ForumLayout = @import("shared.zig").ForumLayout; diff --git a/src/structures/user.zig b/src/structures/user.zig index 6de8fa8..6ccde56 100644 --- a/src/structures/user.zig +++ b/src/structures/user.zig @@ -20,7 +20,7 @@ const OAuth2Scope = @import("shared.zig").OAuth2Scope; const Integration = @import("integration.zig").Integration; const Partial = @import("partial.zig").Partial; - const Record = @import("../json-helper.zig").Record; + const Record = @import("../utils/json.zig").Record; /// https://discord.com/developers/docs/resources/user#user-object pub const User = struct { diff --git a/src/internal.zig b/src/utils/core.zig similarity index 51% rename from src/internal.zig rename to src/utils/core.zig index d785617..de2cc2d 100644 --- a/src/internal.zig +++ b/src/utils/core.zig @@ -15,74 +15,7 @@ //! PERFORMANCE OF THIS SOFTWARE. const std = @import("std"); -const mem = std.mem; -const builtin = @import("builtin"); -const Types = @import("./structures/types.zig"); - -pub const IdentifyProperties = struct { - /// Operating system the shard runs on. - os: []const u8, - /// The "browser" where this shard is running on. - browser: []const u8, - /// The device on which the shard is running. - device: []const u8, - - system_locale: ?[]const u8 = null, // TODO parse this - browser_user_agent: ?[]const u8 = null, - browser_version: ?[]const u8 = null, - os_version: ?[]const u8 = null, - referrer: ?[]const u8 = null, - referring_domain: ?[]const u8 = null, - referrer_current: ?[]const u8 = null, - referring_domain_current: ?[]const u8 = null, - release_channel: ?[]const u8 = null, - client_build_number: ?u64 = null, - client_event_source: ?[]const u8 = null, -}; - -/// https://discord.com/developers/docs/topics/gateway#get-gateway -pub const GatewayInfo = struct { - /// The WSS URL that can be used for connecting to the gateway - url: []const u8, -}; - -/// https://discord.com/developers/docs/events/gateway#session-start-limit-object -pub const GatewaySessionStartLimit = struct { - /// Total number of session starts the current user is allowed - total: u32, - /// Remaining number of session starts the current user is allowed - remaining: u32, - /// Number of milliseconds after which the limit resets - reset_after: u32, - /// Number of identify requests allowed per 5 seconds - max_concurrency: u32, -}; - -/// https://discord.com/developers/docs/topics/gateway#get-gateway-bot -pub const GatewayBotInfo = struct { - url: []const u8, - /// The recommended number of shards to use when connecting - /// - /// See https://discord.com/developers/docs/topics/gateway#sharding - shards: u32, - /// Information on the current session start limit - /// - /// See https://discord.com/developers/docs/topics/gateway#session-start-limit-object - session_start_limit: ?GatewaySessionStartLimit, -}; - -pub const ShardDetails = struct { - /// Bot token which is used to connect to Discord */ - token: []const u8, - /// The URL of the gateway which should be connected to. - url: []const u8 = "wss://gateway.discord.gg", - /// The gateway version which should be used. - version: ?usize = 10, - /// The calculated intent value of the events which the shard should receive. - intents: Types.Intents, - /// Identify properties to use - properties: IdentifyProperties = default_identify_properties, -}; +const Types = @import("../structures/types.zig"); pub const debug = std.log.scoped(.@"discord.zig"); @@ -95,194 +28,6 @@ pub inline fn logif(log: Log, comptime format: []const u8, args: anytype) void { } } -pub const default_identify_properties = IdentifyProperties{ - .os = @tagName(builtin.os.tag), - .browser = "discord.zig", - .device = "discord.zig", -}; - -/// inspired from: -/// https://github.com/tiramisulabs/seyfert/blob/main/src/websocket/structures/timeout.ts -pub fn ConnectQueue(comptime T: type) type { - return struct { - pub const RequestWithShard = struct { - callback: *const fn (self: *RequestWithShard) anyerror!void, - shard: T, - }; - - // ignore this function - // so it becomes a regular dequeue - fn eq(_: void, _: RequestWithShard, _: RequestWithShard) std.math.Order { - return std.math.Order.eq; - } - - dequeue: std.PriorityDequeue(RequestWithShard, void, eq), - allocator: mem.Allocator, - remaining: usize, - interval_time: u64 = 5000, - running: bool = false, - concurrency: usize = 1, - - pub fn init(allocator: mem.Allocator, concurrency: usize, interval_time: u64) !ConnectQueue(T) { - return .{ - .allocator = allocator, - .dequeue = std.PriorityDequeue(RequestWithShard, void, eq).init(allocator, {}), - .remaining = concurrency, - .interval_time = interval_time, - .concurrency = concurrency, - }; - } - - pub fn deinit(self: *ConnectQueue(T)) void { - self.dequeue.deinit(); - } - - pub fn push(self: *ConnectQueue(T), req: RequestWithShard) !void { - if (self.remaining == 0) { - return self.dequeue.add(req); - } - self.remaining -= 1; - - if (!self.running) { - try self.startInterval(); - self.running = true; - } - - if (self.dequeue.count() < self.concurrency) { - // perhaps store this? - const ptr = try self.allocator.create(RequestWithShard); - ptr.* = req; - try req.callback(ptr); - return; - } - - return self.dequeue.add(req); - } - - fn startInterval(self: *ConnectQueue(T)) !void { - while (self.running) { - std.Thread.sleep(std.time.ns_per_ms * (self.interval_time / self.concurrency)); - const req: ?RequestWithShard = self.dequeue.removeMin(); // pop front - - while (self.dequeue.count() == 0 and req == null) {} - - if (req) |r| { - const ptr = try self.allocator.create(RequestWithShard); - ptr.* = r; - try @call(.auto, r.callback, .{ptr}); - return; - } - - if (self.remaining < self.concurrency) { - self.remaining += 1; - } - - if (self.dequeue.count() == 0) { - self.running = false; - } - } - } - }; -} - -pub const Bucket = struct { - /// The queue of requests to acquire an available request. Mapped by (shardId, RequestWithPrio) - queue: std.PriorityQueue(RequestWithPrio, void, Bucket.lessthan), - - limit: usize, - refill_interval: u64, - refill_amount: usize, - - /// The amount of requests that have been used up already. - used: usize = 0, - - /// Whether or not the queue is already processing. - processing: bool = false, - - /// Whether the timeout should be killed because there is already one running - should_stop: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), - - /// The timestamp in milliseconds when the next refill is scheduled. - refills_at: ?u64 = null, - - pub const RequestWithPrio = struct { - callback: *const fn () void, - priority: u32 = 1, - }; - - fn lessthan(_: void, a: RequestWithPrio, b: RequestWithPrio) std.math.Order { - return std.math.order(a.priority, b.priority); - } - - pub fn init(allocator: mem.Allocator, limit: usize, refill_interval: u64, refill_amount: usize) Bucket { - return .{ - .queue = std.PriorityQueue(RequestWithPrio, void, lessthan).init(allocator, {}), - .limit = limit, - .refill_interval = refill_interval, - .refill_amount = refill_amount, - }; - } - - fn remaining(self: *Bucket) usize { - if (self.limit < self.used) { - return 0; - } else { - return self.limit - self.used; - } - } - - pub fn refill(self: *Bucket) std.Thread.SpawnError!void { - // Lower the used amount by the refill amount - self.used = if (self.refill_amount > self.used) 0 else self.used - self.refill_amount; - - // Reset the refills_at timestamp since it just got refilled - self.refills_at = null; - - if (self.used > 0) { - if (self.should_stop.load(.monotonic) == true) { - self.should_stop.store(false, .monotonic); - } - const thread = try std.Thread.spawn(.{}, Bucket.timeout, .{self}); - thread.detach; - self.refills_at = std.time.milliTimestamp() + self.refill_interval; - } - } - - fn timeout(self: *Bucket) void { - while (!self.should_stop.load(.monotonic)) { - self.refill(); - std.time.sleep(std.time.ns_per_ms * self.refill_interval); - } - } - - pub fn processQueue(self: *Bucket) std.Thread.SpawnError!void { - if (self.processing) return; - - while (self.queue.remove()) |first_element| { - if (self.remaining() != 0) { - first_element.callback(); - self.used += 1; - - if (!self.should_stop.load(.monotonic)) { - const thread = try std.Thread.spawn(.{}, Bucket.timeout, .{self}); - thread.detach; - self.refills_at = std.time.milliTimestamp() + self.refill_interval; - } - } else if (self.refills_at) |ra| { - const now = std.time.milliTimestamp(); - if (ra > now) std.time.sleep(std.time.ns_per_ms * (ra - now)); - } - } - - self.processing = false; - } - - pub fn acquire(self: *Bucket, rq: RequestWithPrio) !void { - try self.queue.add(rq); - try self.processQueue(); - } -}; - pub const GatewayDispatchEvent = struct { application_command_permissions_update: ?*const fn (save: *anyopaque, application_command_permissions: Types.ApplicationCommandPermissions) anyerror!void = undefined, auto_moderation_rule_create: ?*const fn (save: *anyopaque, rule: Types.AutoModerationRule) anyerror!void = undefined, diff --git a/src/json-helper.zig b/src/utils/json.zig similarity index 100% rename from src/json-helper.zig rename to src/utils/json.zig diff --git a/src/extra/permissions.zig b/src/utils/permissions.zig similarity index 100% rename from src/extra/permissions.zig rename to src/utils/permissions.zig