add components :)
This commit is contained in:
parent
846b265e07
commit
e8fbc72485
33
README.md
33
README.md
@ -9,39 +9,40 @@ A high-performance bleeding edge Discord library in Zig, featuring full API cove
|
||||
|
||||
```zig
|
||||
const std = @import("std");
|
||||
const Discord = @import("discord.zig");
|
||||
const Discord = @import("discord");
|
||||
const Shard = Discord.Shard;
|
||||
const Intents = Discord.Intents;
|
||||
|
||||
fn ready(_: *Shard, payload: Discord.Ready) !void {
|
||||
std.debug.print("logged in as {s}\n", .{payload.user.username});
|
||||
}
|
||||
|
||||
fn message_create(session: *Shard, message: Discord.Message) !void {
|
||||
if (message.content) |mc| if (std.ascii.eqlIgnoreCase(mc, "!hi")) {
|
||||
var result = try session.sendMessage(message.channel_id, .{ .content = "discord.zig best lib" });
|
||||
if (std.ascii.eqlIgnoreCase(message.content.?, "!hi")) {
|
||||
var result = try session.sendMessage(message.channel_id, .{
|
||||
.content = "hello world from discord.zig",
|
||||
});
|
||||
defer result.deinit();
|
||||
|
||||
switch (result.value) {
|
||||
.left => |e| std.debug.panic("Error: {d}\r{s}\n", .{ e.code, e.message }), // or you may tell the end user the error
|
||||
.right => |m| std.debug.print("Sent: {?s} sent by {s}\n", .{ m.content, m.author.username }),
|
||||
}
|
||||
};
|
||||
const m = result.value.unwrap();
|
||||
std.debug.print("sent: {?s}\n", .{m.content});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = 9999 }){};
|
||||
var handler = Discord.init(gpa.allocator());
|
||||
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var handler = Discord.init(allocator);
|
||||
defer handler.deinit();
|
||||
|
||||
try handler.start(.{
|
||||
.token = std.posix.getenv("TOKEN").?, // or your token
|
||||
.intents = Intents.fromRaw(53608447), // all intents
|
||||
.intents = Discord.Intents.fromRaw(53608447);
|
||||
.token = std.posix.getenv("DISCORD_TOKEN").?,
|
||||
.run = .{ .message_create = &message_create, .ready = &ready },
|
||||
.log = .yes,
|
||||
.options = .{},
|
||||
});
|
||||
errdefer handler.deinit();
|
||||
}
|
||||
```
|
||||
|
||||
## Installation
|
||||
```zig
|
||||
// In your build.zig file
|
||||
|
@ -38,7 +38,7 @@ pub fn build(b: *std.Build) void {
|
||||
.link_libc = true,
|
||||
});
|
||||
|
||||
marin.root_module.addImport("discord.zig", dzig);
|
||||
marin.root_module.addImport("discord", dzig);
|
||||
marin.root_module.addImport("ws", websocket.module("websocket"));
|
||||
marin.root_module.addImport("zlib", zlib.module("zlib"));
|
||||
marin.root_module.addImport("deque", deque.module("zig-deque"));
|
||||
|
@ -154,7 +154,7 @@ fn spawnBuckets(self: *Self) ![][]Shard {
|
||||
fn create(self: *Self, shard_id: usize) !Shard {
|
||||
if (self.shards.get(shard_id)) |s| return s;
|
||||
|
||||
const shard: Shard = try Shard.init(self.allocator, shard_id, .{
|
||||
const shard: Shard = try .init(self.allocator, shard_id, self.options.total_shards, .{
|
||||
.token = self.shard_details.token,
|
||||
.intents = self.shard_details.intents,
|
||||
.options = Shard.ShardOptions{
|
||||
|
@ -1011,7 +1011,7 @@ pub fn parseInto(comptime T: type, allocator: mem.Allocator, value: JsonType) Er
|
||||
|
||||
const fieldname = switch (value) {
|
||||
.string => |slice| slice,
|
||||
else => @panic("can only cast strings for untagged union"),
|
||||
else => @panic("can only cast strings for tagged union"),
|
||||
};
|
||||
|
||||
inline for (unionInfo.fields) |u_field| {
|
||||
|
@ -74,6 +74,7 @@ pub const ShardOptions = struct {
|
||||
ratelimit_options: RatelimitOptions = .{},
|
||||
};
|
||||
|
||||
total_shards: usize,
|
||||
id: usize,
|
||||
|
||||
client: ws.Client,
|
||||
@ -128,6 +129,7 @@ pub fn identify(self: *Self, properties: ?IdentifyProperties) SendError!void {
|
||||
.intents = self.details.intents.toRaw(),
|
||||
.properties = properties orelse default_identify_properties,
|
||||
.token = self.details.token,
|
||||
.shard = &.{ self.id, self.total_shards },
|
||||
},
|
||||
};
|
||||
try self.send(false, data);
|
||||
@ -144,7 +146,7 @@ pub fn identify(self: *Self, properties: ?IdentifyProperties) SendError!void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(allocator: mem.Allocator, shard_id: usize, settings: struct {
|
||||
pub fn init(allocator: mem.Allocator, shard_id: usize, total_shards: usize, settings: struct {
|
||||
token: []const u8,
|
||||
intents: Intents,
|
||||
options: ShardOptions,
|
||||
@ -161,6 +163,7 @@ pub fn init(allocator: mem.Allocator, shard_id: usize, settings: struct {
|
||||
.ratelimit_options = settings.options.ratelimit_options,
|
||||
},
|
||||
.id = shard_id,
|
||||
.total_shards = total_shards,
|
||||
.allocator = allocator,
|
||||
.details = ShardDetails{
|
||||
.token = settings.token,
|
||||
@ -2799,12 +2802,7 @@ pub fn createSticker(
|
||||
defer req.deinit();
|
||||
|
||||
var files = .{file};
|
||||
return req.post2(
|
||||
Types.Sticker,
|
||||
path,
|
||||
sticker,
|
||||
&files,
|
||||
);
|
||||
return req.post2(Types.Sticker, path, sticker, &files);
|
||||
}
|
||||
|
||||
/// Modify the given sticker.
|
||||
|
236
src/structures/component.zig
Normal file
236
src/structures/component.zig
Normal file
@ -0,0 +1,236 @@
|
||||
const Partial = @import("partial.zig").Partial;
|
||||
const Snowflake = @import("snowflake.zig").Snowflake;
|
||||
const Emoji = @import("emoji.zig").Emoji;
|
||||
const ButtonStyles = @import("shared.zig").ButtonStyles;
|
||||
const ChannelTypes = @import("shared.zig").ChannelTypes;
|
||||
const MessageComponentTypes = @import("shared.zig").MessageComponentTypes;
|
||||
|
||||
const zjson = @import("../json.zig");
|
||||
const std = @import("std");
|
||||
|
||||
/// https://discord.com/developers/docs/interactions/message-components#buttons
|
||||
pub const Button = struct {
|
||||
/// 2 for a button
|
||||
type: MessageComponentTypes,
|
||||
/// A button style
|
||||
style: ButtonStyles,
|
||||
/// Text that appears on the button; max 80 characters
|
||||
label: ?[]const u8,
|
||||
/// name, id, and animated
|
||||
emoji: Partial(Emoji),
|
||||
/// Developer-defined identifier for the button; max 100 characters
|
||||
custom_id: ?[]const u8,
|
||||
/// Identifier for a purchasable SKU, only available when using premium-style buttons
|
||||
sku_id: ?Snowflake,
|
||||
/// URL for link-style buttons
|
||||
url: ?[]const u8,
|
||||
/// Whether the button is disabled (defaults to false)
|
||||
disabled: ?bool,
|
||||
};
|
||||
|
||||
pub const SelectOption = struct {
|
||||
/// User-facing name of the option; max 100 characters
|
||||
label: []const u8,
|
||||
/// Dev-defined value of the option; max 100 characters
|
||||
value: []const u8,
|
||||
/// Additional description of the option; max 100 characters
|
||||
description: ?[]const u8,
|
||||
/// id, name, and animated
|
||||
emoji: ?Partial(Emoji),
|
||||
/// Will show this option as selected by default
|
||||
default: ?bool,
|
||||
};
|
||||
|
||||
pub const DefaultValue = struct {
|
||||
/// ID of a user, role, or channel
|
||||
id: Snowflake,
|
||||
/// Type of value that id represents. Either "user", "role", or "channel"
|
||||
type: union(enum) { user, role, channel },
|
||||
};
|
||||
|
||||
/// https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||
pub const SelectMenuString = struct {
|
||||
/// Type of select menu component (text: 3, user: 5, role: 6, mentionable: 7, channels: 8)
|
||||
type: MessageComponentTypes,
|
||||
/// ID for the select menu; max 100 characters
|
||||
custom_id: []const u8,
|
||||
/// Specified choices in a select menu (only required and available for string selects (type 3); max 25
|
||||
/// * options is required for string select menus (component type 3), and unavailable for all other select menu components.
|
||||
options: ?[]SelectOption,
|
||||
/// Placeholder text if nothing is selected; max 150 characters
|
||||
placeholder: ?[]const u8,
|
||||
/// Minimum number of items that must be chosen (defaults to 1); min 0, max 25
|
||||
min_values: ?usize,
|
||||
/// Maximum number of items that can be chosen (defaults to 1); max 25
|
||||
max_values: ?usize,
|
||||
/// Whether select menu is disabled (defaults to false)
|
||||
disabled: ?bool,
|
||||
};
|
||||
|
||||
/// https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||
pub const SelectMenuUsers = struct {
|
||||
/// Type of select menu component (text: 3, user: 5, role: 6, mentionable: 7, channels: 8)
|
||||
type: MessageComponentTypes,
|
||||
/// ID for the select menu; max 100 characters
|
||||
custom_id: []const u8,
|
||||
/// Placeholder text if nothing is selected; max 150 characters
|
||||
placeholder: ?[]const u8,
|
||||
/// List of default values for auto-populated select menu components; number of default values must be in the range defined by min_values and max_values
|
||||
/// *** default_values is only available for auto-populated select menu components, which include user (5), role (6), mentionable (7), and channel (8) components.
|
||||
default_values: ?[]DefaultValue,
|
||||
/// Minimum number of items that must be chosen (defaults to 1); min 0, max 25
|
||||
min_values: ?usize,
|
||||
/// Maximum number of items that can be chosen (defaults to 1); max 25
|
||||
max_values: ?usize,
|
||||
/// Whether select menu is disabled (defaults to false)
|
||||
disabled: ?bool,
|
||||
};
|
||||
|
||||
/// https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||
pub const SelectMenuRoles = struct {
|
||||
/// Type of select menu component (text: 3, user: 5, role: 6, mentionable: 7, channels: 8)
|
||||
type: MessageComponentTypes,
|
||||
/// ID for the select menu; max 100 characters
|
||||
custom_id: []const u8,
|
||||
/// Placeholder text if nothing is selected; max 150 characters
|
||||
placeholder: ?[]const u8,
|
||||
/// List of default values for auto-populated select menu components; number of default values must be in the range defined by min_values and max_values
|
||||
/// *** default_values is only available for auto-populated select menu components, which include user (5), role (6), mentionable (7), and channel (8) components.
|
||||
default_values: ?[]DefaultValue,
|
||||
/// Minimum number of items that must be chosen (defaults to 1); min 0, max 25
|
||||
min_values: ?usize,
|
||||
/// Maximum number of items that can be chosen (defaults to 1); max 25
|
||||
max_values: ?usize,
|
||||
/// Whether select menu is disabled (defaults to false)
|
||||
disabled: ?bool,
|
||||
};
|
||||
|
||||
/// https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||
pub const SelectMenuUsersAndRoles = struct {
|
||||
/// Type of select menu component (text: 3, user: 5, role: 6, mentionable: 7, channels: 8)
|
||||
type: MessageComponentTypes,
|
||||
/// ID for the select menu; max 100 characters
|
||||
custom_id: []const u8,
|
||||
/// Placeholder text if nothing is selected; max 150 characters
|
||||
placeholder: ?[]const u8,
|
||||
/// List of default values for auto-populated select menu components; number of default values must be in the range defined by min_values and max_values
|
||||
/// *** default_values is only available for auto-populated select menu components, which include user (5), role (6), mentionable (7), and channel (8) components.
|
||||
default_values: ?[]DefaultValue,
|
||||
/// Minimum number of items that must be chosen (defaults to 1); min 0, max 25
|
||||
min_values: ?usize,
|
||||
/// Maximum number of items that can be chosen (defaults to 1); max 25
|
||||
max_values: ?usize,
|
||||
/// Whether select menu is disabled (defaults to false)
|
||||
disabled: ?bool,
|
||||
};
|
||||
|
||||
/// https://discord.com/developers/docs/interactions/message-components#select-menus
|
||||
pub const SelectMenuChannels = struct {
|
||||
/// Type of select menu component (text: 3, user: 5, role: 6, mentionable: 7, channels: 8)
|
||||
type: MessageComponentTypes,
|
||||
/// ID for the select menu; max 100 characters
|
||||
custom_id: []const u8,
|
||||
/// List of channel types to include in the channel select component (type 8)
|
||||
/// ** channel_types can only be used for channel select menu components.
|
||||
channel_types: ?[]ChannelTypes,
|
||||
/// Placeholder text if nothing is selected; max 150 characters
|
||||
placeholder: ?[]const u8,
|
||||
/// List of default values for auto-populated select menu components; number of default values must be in the range defined by min_values and max_values
|
||||
/// *** default_values is only available for auto-populated select menu components, which include user (5), role (6), mentionable (7), and channel (8) components.
|
||||
default_values: ?[]DefaultValue,
|
||||
/// Minimum number of items that must be chosen (defaults to 1); min 0, max 25
|
||||
min_values: ?usize,
|
||||
/// Maximum number of items that can be chosen (defaults to 1); max 25
|
||||
max_values: ?usize,
|
||||
/// Whether select menu is disabled (defaults to false)
|
||||
disabled: ?bool,
|
||||
};
|
||||
|
||||
pub const SelectMenu = union(MessageComponentTypes) {
|
||||
SelectMenu: SelectMenuString,
|
||||
SelectMenuUsers: SelectMenuUsers,
|
||||
SelectMenuRoles: SelectMenuRoles,
|
||||
SelectMenuUsersAndRoles: SelectMenuUsersAndRoles,
|
||||
SelectMenuChannels: SelectMenuChannels,
|
||||
|
||||
pub fn toJson(allocator: std.mem.Allocator, value: zjson.JsonType) !@This() {
|
||||
if (!value.is(.object))
|
||||
@panic("coulnd't match against non-object type");
|
||||
|
||||
switch (value.object.get("type") orelse @panic("couldn't find property `type`")) {
|
||||
.number => |num| switch (num) {
|
||||
.integer => |int| return switch (@as(MessageComponentTypes, @enumFromInt(int))) {
|
||||
.SelectMenu => .{ .SelectMenu = try zjson.parseInto(SelectMenuString, allocator, value) },
|
||||
.SelectMenuUsers => .{ .SelectMenuUsers = try zjson.parseInto(SelectMenuUsers, allocator, value) },
|
||||
.SelectMenuRoles => .{ .SelectMenuRoles = try zjson.parseInto(SelectMenuRoles, allocator, value) },
|
||||
.SelectMenuUsersAndRoles => .{ .SelectMenuUsersAndRoles = try zjson.parseInto(SelectMenuUsersAndRoles, allocator, value) },
|
||||
.SelectMenuChannels => .{ .SelectMenuChannels = try zjson.parseInto(SelectMenuChannels, allocator, value) },
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
else => @panic("got type but couldn't match against non enum member `type`"),
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
pub const InputTextStyles = enum(u4) {
|
||||
Short = 1,
|
||||
Paragraph,
|
||||
};
|
||||
|
||||
pub const InputText = struct {
|
||||
/// 4 for a text input
|
||||
type: MessageComponentTypes,
|
||||
/// Developer-defined identifier for the input; max 100 characters
|
||||
custom_id: []const u8,
|
||||
/// The Text Input Style
|
||||
style: InputTextStyles,
|
||||
/// Label for this component; max 45 characters
|
||||
label: []const u8,
|
||||
/// Minimum input length for a text input; min 0, max 4000
|
||||
min_length: ?usize,
|
||||
/// Maximum input length for a text input; min 1, max 4000
|
||||
max_length: ?usize,
|
||||
/// Whether this component is required to be filled (defaults to true)
|
||||
required: ?bool,
|
||||
/// Pre-filled value for this component; max 4000 characters
|
||||
value: ?[]const u8,
|
||||
/// Custom placeholder text if the input is empty; max 100 characters
|
||||
placeholder: ?[]const u8,
|
||||
};
|
||||
|
||||
pub const MessageComponent = union(MessageComponentTypes) {
|
||||
ActionRow: []MessageComponent,
|
||||
Button: Button,
|
||||
SelectMenu: SelectMenuString,
|
||||
InputText: InputText,
|
||||
SelectMenuUsers: SelectMenuUsers,
|
||||
SelectMenuRoles: SelectMenuRoles,
|
||||
SelectMenuUsersAndRoles: SelectMenuUsersAndRoles,
|
||||
SelectMenuChannels: SelectMenuChannels,
|
||||
|
||||
pub fn toJson(allocator: std.mem.Allocator, value: zjson.JsonType) !@This() {
|
||||
if (!value.is(.object))
|
||||
@panic("coulnd't match against non-object type");
|
||||
|
||||
switch (value.object.get("type") orelse @panic("couldn't find property `type`")) {
|
||||
.number => |num| switch (num) {
|
||||
.integer => |int| return switch (@as(MessageComponentTypes, @enumFromInt(int))) {
|
||||
.ActionRow => .{ .ActionRow = try zjson.parseInto([]MessageComponent, allocator, value) },
|
||||
.Button => .{ .Button = try zjson.parseInto(Button, allocator, value) },
|
||||
.SelectMenu => .{ .SelectMenu = try zjson.parseInto(SelectMenuString, allocator, value) },
|
||||
.InputText => .{ .InputText = try zjson.parseInto(InputText, allocator, value) },
|
||||
.SelectMenuUsers => .{ .SelectMenuUsers = try zjson.parseInto(SelectMenuUsers, allocator, value) },
|
||||
.SelectMenuRoles => .{ .SelectMenuRoles = try zjson.parseInto(SelectMenuRoles, allocator, value) },
|
||||
.SelectMenuUsersAndRoles => .{ .SelectMenuUsersAndRoles = try zjson.parseInto(SelectMenuUsersAndRoles, allocator, value) },
|
||||
.SelectMenuChannels => .{ .SelectMenuChannels = try zjson.parseInto(SelectMenuChannels, allocator, value) },
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
else => @panic("got type but couldn't match against non enum member `type`"),
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
};
|
@ -35,7 +35,7 @@ const ThreadMember = @import("thread.zig").ThreadMember;
|
||||
const Embed = @import("embed.zig").Embed;
|
||||
const WelcomeScreenChannel = @import("channel.zig").WelcomeScreenChannel;
|
||||
const AllowedMentions = @import("channel.zig").AllowedMentions;
|
||||
const MessageComponent = @import("message.zig").MessageComponent;
|
||||
const MessageComponent = @import("component.zig").MessageComponent;
|
||||
const Sticker = @import("sticker.zig").Sticker;
|
||||
const Partial = @import("partial.zig").Partial;
|
||||
const ReactionType = @import("message.zig").ReactionType;
|
||||
|
@ -33,9 +33,7 @@ const Poll = @import("poll.zig").Poll;
|
||||
const AvatarDecorationData = @import("user.zig").AvatarDecorationData;
|
||||
const MessageActivityTypes = @import("shared.zig").MessageActivityTypes;
|
||||
const Partial = @import("partial.zig").Partial;
|
||||
|
||||
/// TODO: fix this
|
||||
pub const MessageComponent = isize;
|
||||
const MessageComponent = @import("component.zig").MessageComponent;
|
||||
|
||||
/// https://discord.com/developers/docs/resources/channel#message-object
|
||||
pub const Message = struct {
|
||||
|
@ -27,6 +27,7 @@ pub usingnamespace @import("auditlog.zig");
|
||||
pub usingnamespace @import("automod.zig");
|
||||
pub usingnamespace @import("channel.zig");
|
||||
pub usingnamespace @import("command.zig");
|
||||
pub usingnamespace @import("component.zig");
|
||||
pub usingnamespace @import("embed.zig");
|
||||
pub usingnamespace @import("emoji.zig");
|
||||
pub usingnamespace @import("gateway.zig");
|
||||
|
@ -15,7 +15,7 @@
|
||||
//! PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
const std = @import("std");
|
||||
const Discord = @import("discord.zig");
|
||||
const Discord = @import("discord");
|
||||
const Shard = Discord.Shard;
|
||||
const Intents = Discord.Intents;
|
||||
|
||||
@ -26,18 +26,22 @@ fn ready(_: *Shard, payload: Discord.Ready) !void {
|
||||
}
|
||||
|
||||
fn message_create(session: *Shard, message: Discord.Message) !void {
|
||||
if (message.content) |mc| if (std.ascii.eqlIgnoreCase(mc, "!hi")) {
|
||||
if (message.content != null and std.ascii.eqlIgnoreCase(message.content.?, "!hi")) {
|
||||
var result = try session.sendMessage(message.channel_id, .{ .content = "hi :)" });
|
||||
defer result.deinit();
|
||||
|
||||
const m = result.value.unwrap();
|
||||
std.debug.print("sent: {?s}\n", .{m.content});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = 9999 }){};
|
||||
var handler = Discord.init(gpa.allocator());
|
||||
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var handler = Discord.init(allocator);
|
||||
defer handler.deinit();
|
||||
|
||||
try handler.start(.{
|
||||
.token = std.posix.getenv("DISCORD_TOKEN").?,
|
||||
.intents = Intents.fromRaw(INTENTS),
|
||||
@ -45,5 +49,4 @@ pub fn main() !void {
|
||||
.log = .yes,
|
||||
.options = .{},
|
||||
});
|
||||
errdefer handler.deinit();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user