minor refactor
This commit is contained in:
parent
195c5945eb
commit
b8c42bb22c
@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
const zlib = b.dependency("zlib", .{});
|
const zlib = b.dependency("zlib", .{});
|
||||||
|
|
||||||
const dzig = b.addModule("discord.zig", .{
|
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,
|
.link_libc = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
|
|
||||||
const lib = b.addStaticLibrary(.{
|
const lib = b.addStaticLibrary(.{
|
||||||
.name = "discord.zig",
|
.name = "discord.zig",
|
||||||
.root_source_file = b.path("src/discord.zig"),
|
.root_source_file = b.path("lib/discord.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
22
src/cache.zig → src/cache/cache.zig
vendored
22
src/cache.zig → src/cache/cache.zig
vendored
@ -4,23 +4,23 @@ const std = @import("std");
|
|||||||
/// otherwise, simply do TableTemplate{}
|
/// otherwise, simply do TableTemplate{}
|
||||||
/// this is a template for the cache tables
|
/// this is a template for the cache tables
|
||||||
pub const TableTemplate = struct {
|
pub const TableTemplate = struct {
|
||||||
comptime User: type = @import("./config.zig").StoredUser,
|
comptime User: type = @import("../config.zig").StoredUser,
|
||||||
comptime Guild: type = @import("./config.zig").StoredGuild,
|
comptime Guild: type = @import("../config.zig").StoredGuild,
|
||||||
comptime Channel: type = @import("./config.zig").StoredChannel,
|
comptime Channel: type = @import("../config.zig").StoredChannel,
|
||||||
comptime Emoji: type = @import("./config.zig").StoredEmoji,
|
comptime Emoji: type = @import("../config.zig").StoredEmoji,
|
||||||
comptime Message: type = @import("./config.zig").StoredMessage,
|
comptime Message: type = @import("../config.zig").StoredMessage,
|
||||||
comptime Role: type = @import("./config.zig").StoredRole,
|
comptime Role: type = @import("../config.zig").StoredRole,
|
||||||
comptime Sticker: type = @import("./config.zig").StoredSticker,
|
comptime Sticker: type = @import("../config.zig").StoredSticker,
|
||||||
comptime Reaction: type = @import("./config.zig").StoredReaction,
|
comptime Reaction: type = @import("../config.zig").StoredReaction,
|
||||||
comptime Member: type = @import("./config.zig").StoredMember,
|
comptime Member: type = @import("../config.zig").StoredMember,
|
||||||
comptime Thread: type = @import("./config.zig").StoredChannel,
|
comptime Thread: type = @import("../config.zig").StoredChannel,
|
||||||
};
|
};
|
||||||
|
|
||||||
// by default this caches everything
|
// by default this caches everything
|
||||||
// therefore we'll allow custom cache tables
|
// therefore we'll allow custom cache tables
|
||||||
pub fn CacheTables(comptime Table: TableTemplate) type {
|
pub fn CacheTables(comptime Table: TableTemplate) type {
|
||||||
return struct {
|
return struct {
|
||||||
const Snowflake = @import("./structures/snowflake.zig").Snowflake;
|
const Snowflake = @import("../structures/snowflake.zig").Snowflake;
|
||||||
|
|
||||||
const StoredUser: type = Table.User;
|
const StoredUser: type = Table.User;
|
||||||
const StoredGuild: type = Table.Guild;
|
const StoredGuild: type = Table.Guild;
|
@ -4,6 +4,7 @@ const PremiumTypes = @import("./structures/shared.zig").PremiumTypes;
|
|||||||
const Snowflake = @import("./structures/snowflake.zig").Snowflake;
|
const Snowflake = @import("./structures/snowflake.zig").Snowflake;
|
||||||
const AvatarDecorationData = @import("./structures/user.zig").AvatarDecorationData;
|
const AvatarDecorationData = @import("./structures/user.zig").AvatarDecorationData;
|
||||||
|
|
||||||
|
|
||||||
/// https://discord.com/developers/docs/resources/user#user-object
|
/// https://discord.com/developers/docs/resources/user#user-object
|
||||||
/// modify this to your liking
|
/// modify this to your liking
|
||||||
pub const StoredUser = struct {
|
pub const StoredUser = struct {
|
||||||
|
@ -29,5 +29,5 @@ pub const DiscordError = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn Result(comptime T: type) type {
|
pub fn Result(comptime T: type) type {
|
||||||
return @import("json-helper.zig").OwnedEither(DiscordError, T);
|
return @import("./utils/json.zig").OwnedEither(DiscordError, T);
|
||||||
}
|
}
|
||||||
|
0
src/http/api.zig
Normal file
0
src/http/api.zig
Normal file
@ -18,10 +18,10 @@ const std = @import("std");
|
|||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const http = std.http;
|
const http = std.http;
|
||||||
const json = std.json;
|
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 Result = @import("../errors.zig").Result;
|
||||||
pub const DiscordError = @import("errors.zig").DiscordError;
|
pub const DiscordError = @import("../errors.zig").DiscordError;
|
||||||
|
|
||||||
pub const BASE_URL = "https://discord.com/api/v10";
|
pub const BASE_URL = "https://discord.com/api/v10";
|
||||||
|
|
@ -67,8 +67,6 @@ pub const PermissionStrings = @import("structures/types.zig").PermissionStrings;
|
|||||||
pub const GatewayCloseEventCodes = @import("structures/types.zig").GatewayCloseEventCodes;
|
pub const GatewayCloseEventCodes = @import("structures/types.zig").GatewayCloseEventCodes;
|
||||||
pub const GatewayOpcodes = @import("structures/types.zig").GatewayOpcodes;
|
pub const GatewayOpcodes = @import("structures/types.zig").GatewayOpcodes;
|
||||||
pub const GatewayDispatchEventNames = @import("structures/types.zig").GatewayDispatchEventNames;
|
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 InteractionResponseTypes = @import("structures/types.zig").InteractionResponseTypes;
|
||||||
pub const SortOrderTypes = @import("structures/types.zig").SortOrderTypes;
|
pub const SortOrderTypes = @import("structures/types.zig").SortOrderTypes;
|
||||||
pub const ForumLayout = @import("structures/types.zig").ForumLayout;
|
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;
|
pub const GatewayPayload = @import("structures/types.zig").GatewayPayload;
|
||||||
// END USING NAMESPACE
|
// END USING NAMESPACE
|
||||||
|
|
||||||
pub const CacheTables = @import("cache.zig").CacheTables;
|
pub const CacheTables = @import("cache/cache.zig").CacheTables;
|
||||||
pub const CacheLike = @import("cache.zig").CacheLike;
|
pub const CacheLike = @import("cache/cache.zig").CacheLike;
|
||||||
pub const DefaultCache = @import("cache.zig").DefaultCache;
|
pub const DefaultCache = @import("cache/cache.zig").DefaultCache;
|
||||||
|
|
||||||
pub const Permissions = @import("extra/permissions.zig").Permissions;
|
pub const Permissions = @import("utils/permissions.zig").Permissions;
|
||||||
pub const Shard = @import("shard.zig").Shard;
|
pub const Shard = @import("shard/shard.zig").Shard;
|
||||||
pub const zjson = @compileError("Deprecated.");
|
pub const zjson = @compileError("Deprecated.");
|
||||||
|
|
||||||
pub const Internal = @import("internal.zig");
|
pub const Internal = @import("utils/core.zig");
|
||||||
const GatewayDispatchEvent = Internal.GatewayDispatchEvent;
|
const GatewayDispatchEvent = Internal.GatewayDispatchEvent;
|
||||||
const GatewayBotInfo = Internal.GatewayBotInfo;
|
const GatewayBotInfo = @import("shard/util.zig").GatewayBotInfo;
|
||||||
const Log = Internal.Log;
|
const Log = Internal.Log;
|
||||||
|
|
||||||
// sharder
|
// 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 FetchReq = @import("http/http.zig").FetchReq;
|
||||||
pub const FileData = @import("http.zig").FileData;
|
pub const FileData = @import("http/http.zig").FileData;
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
@ -421,6 +419,9 @@ pub fn deinit(self: *Session) void {
|
|||||||
self.deinit();
|
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 {
|
pub fn start(self: *Session, settings: struct {
|
||||||
token: []const u8,
|
token: []const u8,
|
||||||
intents: Intents,
|
intents: Intents,
|
106
src/shard/bucket.zig
Normal file
106
src/shard/bucket.zig
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
};
|
87
src/shard/connect_queue.zig
Normal file
87
src/shard/connect_queue.zig
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
179
src/shard/intents.zig
Normal file
179
src/shard/intents.zig
Normal file
@ -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;
|
@ -28,29 +28,31 @@ const http = std.http;
|
|||||||
const zlib = @import("zlib");
|
const zlib = @import("zlib");
|
||||||
const json = @import("std").json;
|
const json = @import("std").json;
|
||||||
|
|
||||||
const Result = @import("errors.zig").Result;
|
const Result = @import("../errors.zig").Result;
|
||||||
|
|
||||||
const IdentifyProperties = @import("internal.zig").IdentifyProperties;
|
const IdentifyProperties = @import("util.zig").IdentifyProperties;
|
||||||
const GatewayInfo = @import("internal.zig").GatewayInfo;
|
const GatewayInfo = @import("util.zig").GatewayInfo;
|
||||||
const GatewayBotInfo = @import("internal.zig").GatewayBotInfo;
|
const GatewayBotInfo = @import("util.zig").GatewayBotInfo;
|
||||||
const GatewaySessionStartLimit = @import("internal.zig").GatewaySessionStartLimit;
|
const GatewaySessionStartLimit = @import("util.zig").GatewaySessionStartLimit;
|
||||||
const ShardDetails = @import("internal.zig").ShardDetails;
|
const ShardDetails = @import("util.zig").ShardDetails;
|
||||||
const internalLogif = @import("internal.zig").logif;
|
const internalLogif = @import("../utils/core.zig").logif;
|
||||||
|
|
||||||
const Log = @import("internal.zig").Log;
|
const Log = @import("../utils/core.zig").Log;
|
||||||
const GatewayDispatchEvent = @import("internal.zig").GatewayDispatchEvent;
|
const GatewayDispatchEvent = @import("../utils/core.zig").GatewayDispatchEvent;
|
||||||
const Bucket = @import("internal.zig").Bucket;
|
const Bucket = @import("bucket.zig").Bucket;
|
||||||
const default_identify_properties = @import("internal.zig").default_identify_properties;
|
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 Opcode = Types.GatewayOpcodes;
|
||||||
const Intents = Types.Intents;
|
const Intents = @import("intents.zig").Intents;
|
||||||
|
|
||||||
const Snowflake = Types.Snowflake;
|
const Snowflake = Types.Snowflake;
|
||||||
const FetchReq = @import("http.zig").FetchReq;
|
const FetchReq = @import("../http/http.zig").FetchReq;
|
||||||
const MakeRequestError = @import("http.zig").MakeRequestError;
|
const MakeRequestError = @import("../http/http.zig").MakeRequestError;
|
||||||
const Partial = Types.Partial;
|
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 {
|
pub fn Shard(comptime Table: TableTemplate) type {
|
||||||
return struct {
|
return struct {
|
||||||
@ -106,7 +108,7 @@ pub fn Shard(comptime Table: TableTemplate) type {
|
|||||||
log: Log = .no,
|
log: Log = .no,
|
||||||
|
|
||||||
/// actual cache
|
/// actual cache
|
||||||
cache_handler: *@import("cache.zig").CacheTables(Table),
|
cache_handler: *CacheTables(Table),
|
||||||
|
|
||||||
pub fn resumable(self: *Self) bool {
|
pub fn resumable(self: *Self) bool {
|
||||||
return self.resume_gateway_url != null and
|
return self.resume_gateway_url != null and
|
||||||
@ -160,7 +162,7 @@ pub fn Shard(comptime Table: TableTemplate) type {
|
|||||||
options: ShardOptions,
|
options: ShardOptions,
|
||||||
run: GatewayDispatchEvent,
|
run: GatewayDispatchEvent,
|
||||||
log: Log,
|
log: Log,
|
||||||
cache: *@import("cache.zig").CacheTables(Table),
|
cache: *CacheTables(Table),
|
||||||
sharder_pool: ?*std.Thread.Pool = null,
|
sharder_pool: ?*std.Thread.Pool = null,
|
||||||
}) zlib.Error!Self {
|
}) zlib.Error!Self {
|
||||||
return Self{
|
return Self{
|
||||||
@ -933,7 +935,7 @@ pub fn Shard(comptime Table: TableTemplate) type {
|
|||||||
/// the create message payload
|
/// the create message payload
|
||||||
create_message: Partial(Types.CreateMessage),
|
create_message: Partial(Types.CreateMessage),
|
||||||
/// the files to send, must be one of FileData.type
|
/// 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
|
/// same as `sendMessage` but acceps a files field
|
||||||
@ -1448,7 +1450,7 @@ pub fn Shard(comptime Table: TableTemplate) type {
|
|||||||
|
|
||||||
pub const StartThreadInForumOrMediaChannelWithFiles = struct {
|
pub const StartThreadInForumOrMediaChannelWithFiles = struct {
|
||||||
start_thread: Types.StartThreadFromMessage,
|
start_thread: Types.StartThreadFromMessage,
|
||||||
files: []@import("http.zig").FileData,
|
files: []FileData,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// same as `startThreadInForumOrMediaChannel`
|
/// same as `startThreadInForumOrMediaChannel`
|
||||||
@ -2862,7 +2864,7 @@ pub fn Shard(comptime Table: TableTemplate) type {
|
|||||||
self: *Self,
|
self: *Self,
|
||||||
guild_id: Snowflake,
|
guild_id: Snowflake,
|
||||||
sticker: Types.CreateModifyGuildSticker,
|
sticker: Types.CreateModifyGuildSticker,
|
||||||
file: @import("http.zig").FileData,
|
file: FileData,
|
||||||
) RequestFailedError!Result(Types.Sticker) {
|
) RequestFailedError!Result(Types.Sticker) {
|
||||||
var buf: [256]u8 = undefined;
|
var buf: [256]u8 = undefined;
|
||||||
const path = try std.fmt.bufPrint(&buf, "/guilds/{d}/stickers", .{guild_id.into()});
|
const path = try std.fmt.bufPrint(&buf, "/guilds/{d}/stickers", .{guild_id.into()});
|
@ -14,20 +14,21 @@
|
|||||||
//! OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
//! OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
//! PERFORMANCE OF THIS SOFTWARE.
|
//! PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
const Intents = @import("./structures/types.zig").Intents;
|
const Intents = @import("intents.zig").Intents;
|
||||||
const Snowflake = @import("./structures/snowflake.zig").Snowflake;
|
const Snowflake = @import("../structures/snowflake.zig").Snowflake;
|
||||||
const GatewayBotInfo = @import("internal.zig").GatewayBotInfo;
|
const GatewayBotInfo = @import("util.zig").GatewayBotInfo;
|
||||||
const IdentifyProperties = @import("internal.zig").IdentifyProperties;
|
const IdentifyProperties = @import("util.zig").IdentifyProperties;
|
||||||
const internalLogif = @import("internal.zig").logif;
|
const internalLogif = @import("../utils/core.zig").logif;
|
||||||
const ShardDetails = @import("internal.zig").ShardDetails;
|
const ShardDetails = @import("util.zig").ShardDetails;
|
||||||
const ConnectQueue = @import("internal.zig").ConnectQueue;
|
const ConnectQueue = @import("connect_queue.zig").ConnectQueue;
|
||||||
const GatewayDispatchEvent = @import("internal.zig").GatewayDispatchEvent;
|
const GatewayDispatchEvent = @import("../utils/core.zig").GatewayDispatchEvent;
|
||||||
const Log = @import("internal.zig").Log;
|
const Log = @import("../utils/core.zig").Log;
|
||||||
const Shard = @import("shard.zig").Shard;
|
const Shard = @import("shard.zig").Shard;
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const debug = @import("internal.zig").debug;
|
const debug = @import("../utils/core.zig").debug;
|
||||||
const TableTemplate = @import("cache.zig").TableTemplate;
|
const TableTemplate = @import("../cache/cache.zig").TableTemplate;
|
||||||
|
const CacheTables = @import("../cache/cache.zig").CacheTables;
|
||||||
|
|
||||||
pub fn ShardManager(comptime Table: TableTemplate) type {
|
pub fn ShardManager(comptime Table: TableTemplate) type {
|
||||||
return struct {
|
return struct {
|
||||||
@ -50,7 +51,7 @@ pub fn ShardManager(comptime Table: TableTemplate) type {
|
|||||||
log: Log,
|
log: Log,
|
||||||
|
|
||||||
// must be initialised
|
// must be initialised
|
||||||
cache: *@import("cache.zig").CacheTables(Table),
|
cache: *CacheTables(Table),
|
||||||
|
|
||||||
pub const ShardData = struct {
|
pub const ShardData = struct {
|
||||||
/// resume seq to resume connections
|
/// resume seq to resume connections
|
||||||
@ -87,11 +88,11 @@ pub fn ShardManager(comptime Table: TableTemplate) type {
|
|||||||
options: SessionOptions,
|
options: SessionOptions,
|
||||||
run: GatewayDispatchEvent,
|
run: GatewayDispatchEvent,
|
||||||
log: Log,
|
log: Log,
|
||||||
cache: @import("cache.zig").TableTemplate,
|
cache: TableTemplate,
|
||||||
}) mem.Allocator.Error!Self {
|
}) mem.Allocator.Error!Self {
|
||||||
const concurrency = settings.options.info.session_start_limit.?.max_concurrency;
|
const concurrency = settings.options.info.session_start_limit.?.max_concurrency;
|
||||||
const cache = try allocator.create(@import("cache.zig").CacheTables(Table));
|
const cache = try allocator.create(CacheTables(Table));
|
||||||
cache.* = @import("cache.zig").CacheTables(Table).defaults(allocator);
|
cache.* = CacheTables(Table).defaults(allocator);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
59
src/shard/util.zig
Normal file
59
src/shard/util.zig
Normal file
@ -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,
|
||||||
|
};
|
||||||
|
|
@ -21,7 +21,7 @@ const Partial = @import("partial.zig").Partial;
|
|||||||
const User = @import("user.zig").User;
|
const User = @import("user.zig").User;
|
||||||
const Team = @import("team.zig").Team;
|
const Team = @import("team.zig").Team;
|
||||||
const Guild = @import("guild.zig").Guild;
|
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
|
/// https://discord.com/developers/docs/resources/application#application-object
|
||||||
pub const Application = struct {
|
pub const Application = struct {
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
const InteractionResponseTypes = @import("shared.zig").InteractionResponseTypes;
|
const InteractionResponseTypes = @import("shared.zig").InteractionResponseTypes;
|
||||||
const InteractionContextType = @import("command.zig").InteractionContextType;
|
const InteractionContextType = @import("command.zig").InteractionContextType;
|
||||||
const Entitlement = @import("monetization.zig").Entitlement;
|
const Entitlement = @import("monetization.zig").Entitlement;
|
||||||
const Record = @import("../json-helper.zig").Record;
|
const Record = @import("../utils/json.zig").Record;
|
||||||
|
|
||||||
pub const Interaction = struct {
|
pub const Interaction = struct {
|
||||||
/// Id of the interaction
|
/// Id of the interaction
|
||||||
|
@ -15,12 +15,13 @@
|
|||||||
//! PERFORMANCE OF THIS SOFTWARE.
|
//! PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const builtin = std.builtin;
|
||||||
|
|
||||||
pub fn Partial(comptime T: type) type {
|
pub fn Partial(comptime T: type) type {
|
||||||
const info = @typeInfo(T);
|
const info = @typeInfo(T);
|
||||||
switch (info) {
|
switch (info) {
|
||||||
.@"struct" => |s| {
|
.@"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| {
|
inline for (s.fields) |field| {
|
||||||
if (field.is_comptime) {
|
if (field.is_comptime) {
|
||||||
@compileError("Cannot make Partial of " ++ @typeName(T) ++ ", it has a comptime field " ++ field.name);
|
@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 default_value: optional_type = null;
|
||||||
const aligned_ptr: *align(field.alignment) const anyopaque = @alignCast(@ptrCast(&default_value));
|
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,
|
.alignment = field.alignment,
|
||||||
.default_value_ptr = aligned_ptr,
|
.default_value_ptr = aligned_ptr,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
@ -40,9 +41,9 @@ pub fn Partial(comptime T: type) type {
|
|||||||
}};
|
}};
|
||||||
fields = fields ++ optional_field;
|
fields = fields ++ optional_field;
|
||||||
}
|
}
|
||||||
const partial_type_info: std.builtin.Type = .{ .@"struct" = .{
|
const partial_type_info: builtin.Type = .{ .@"struct" = .{
|
||||||
.backing_integer = s.backing_integer,
|
.backing_integer = s.backing_integer,
|
||||||
.decls = &[_]std.builtin.Type.Declaration{},
|
.decls = &[_]builtin.Type.Declaration{},
|
||||||
.fields = fields,
|
.fields = fields,
|
||||||
.is_tuple = s.is_tuple,
|
.is_tuple = s.is_tuple,
|
||||||
.layout = s.layout,
|
.layout = s.layout,
|
||||||
|
@ -1430,181 +1430,6 @@ pub const GuildFeatures = enum {
|
|||||||
RESUMED,
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// - 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
|
|
||||||
pub const Intents = GatewayIntents;
|
|
||||||
|
|
||||||
/// https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionresponsetype
|
/// https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactionresponsetype
|
||||||
pub const InteractionResponseTypes = enum(u4) {
|
pub const InteractionResponseTypes = enum(u4) {
|
||||||
|
@ -66,8 +66,6 @@
|
|||||||
pub const GatewayCloseEventCodes = @import("shared.zig").GatewayCloseEventCodes;
|
pub const GatewayCloseEventCodes = @import("shared.zig").GatewayCloseEventCodes;
|
||||||
pub const GatewayOpcodes = @import("shared.zig").GatewayOpcodes;
|
pub const GatewayOpcodes = @import("shared.zig").GatewayOpcodes;
|
||||||
pub const GatewayDispatchEventNames = @import("shared.zig").GatewayDispatchEventNames;
|
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 InteractionResponseTypes = @import("shared.zig").InteractionResponseTypes;
|
||||||
pub const SortOrderTypes = @import("shared.zig").SortOrderTypes;
|
pub const SortOrderTypes = @import("shared.zig").SortOrderTypes;
|
||||||
pub const ForumLayout = @import("shared.zig").ForumLayout;
|
pub const ForumLayout = @import("shared.zig").ForumLayout;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
const OAuth2Scope = @import("shared.zig").OAuth2Scope;
|
const OAuth2Scope = @import("shared.zig").OAuth2Scope;
|
||||||
const Integration = @import("integration.zig").Integration;
|
const Integration = @import("integration.zig").Integration;
|
||||||
const Partial = @import("partial.zig").Partial;
|
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
|
/// https://discord.com/developers/docs/resources/user#user-object
|
||||||
pub const User = struct {
|
pub const User = struct {
|
||||||
|
@ -15,74 +15,7 @@
|
|||||||
//! PERFORMANCE OF THIS SOFTWARE.
|
//! PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const Types = @import("../structures/types.zig");
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const debug = std.log.scoped(.@"discord.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 {
|
pub const GatewayDispatchEvent = struct {
|
||||||
application_command_permissions_update: ?*const fn (save: *anyopaque, application_command_permissions: Types.ApplicationCommandPermissions) anyerror!void = undefined,
|
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,
|
auto_moderation_rule_create: ?*const fn (save: *anyopaque, rule: Types.AutoModerationRule) anyerror!void = undefined,
|
Loading…
x
Reference in New Issue
Block a user