a
This commit is contained in:
parent
f1f723d531
commit
0412d6b404
24
README.md
24
README.md
@ -71,3 +71,27 @@ Contributions are welcome! Please open an issue or pull request if you'd like to
|
|||||||
| voice_channel_effect_send | ❌ |
|
| voice_channel_effect_send | ❌ |
|
||||||
| voice_state_update | ❌ |
|
| voice_state_update | ❌ |
|
||||||
| voice_server_update | ❌ |
|
| voice_server_update | ❌ |
|
||||||
|
|
||||||
|
## http methods missing
|
||||||
|
| Endpoint | Support |
|
||||||
|
|----------------------------------------|---------|
|
||||||
|
| Application related | ❌ |
|
||||||
|
| Audit log | ❌ |
|
||||||
|
| Automod | ❌ |
|
||||||
|
| Channel related | ✅ |
|
||||||
|
| Emoji related | ✅ |
|
||||||
|
| Entitlement related | ❌ |
|
||||||
|
| Guild related | ✅ |
|
||||||
|
| Guild Scheduled Event related | ❌ |
|
||||||
|
| Guild template related | ❌ |
|
||||||
|
| Invite related | ✅ |
|
||||||
|
| Message related | ✅ |
|
||||||
|
| Poll related | ✅ |
|
||||||
|
| SKU related | ❌ |
|
||||||
|
| Soundboard related | ❌ |
|
||||||
|
| Stage Instance related | ❌ |
|
||||||
|
| Sticker related | ❌ |
|
||||||
|
| Subscription related | ❌ |
|
||||||
|
| User related | ✅ |
|
||||||
|
| Voice related | ❌ |
|
||||||
|
| Webhook related | ❌ |
|
||||||
|
52
src/http.zig
52
src/http.zig
@ -40,14 +40,19 @@ pub const FetchReq = struct {
|
|||||||
token: []const u8,
|
token: []const u8,
|
||||||
client: http.Client,
|
client: http.Client,
|
||||||
body: std.ArrayList(u8),
|
body: std.ArrayList(u8),
|
||||||
|
/// internal
|
||||||
|
extra_headers: std.ArrayList(http.Header),
|
||||||
|
query_params: std.StringArrayHashMap([]const u8),
|
||||||
|
|
||||||
pub fn init(allocator: mem.Allocator, token: []const u8) FetchReq {
|
pub fn init(allocator: mem.Allocator, token: []const u8) FetchReq {
|
||||||
const client = http.Client{ .allocator = allocator };
|
const client = http.Client{ .allocator = allocator };
|
||||||
return FetchReq{
|
return FetchReq{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.client = client,
|
.client = client,
|
||||||
.body = std.ArrayList(u8).init(allocator),
|
|
||||||
.token = token,
|
.token = token,
|
||||||
|
.body = std.ArrayList(u8).init(allocator),
|
||||||
|
.extra_headers = std.ArrayList(http.Header).init(allocator),
|
||||||
|
.query_params = std.StringArrayHashMap([]const u8).init(allocator),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +61,36 @@ pub const FetchReq = struct {
|
|||||||
self.body.deinit();
|
self.body.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addHeader(self: *FetchReq, name: []const u8, value: []const u8) !void {
|
||||||
|
try self.extra_headers.append(http.Header{ .name = name, .value = value });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addQueryParam(self: *FetchReq, name: []const u8, value: []const u8) !void {
|
||||||
|
try self.query_params.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn formatQueryParams(self: *FetchReq) ![]const u8 {
|
||||||
|
var query = std.ArrayListUnmanaged(u8){};
|
||||||
|
const writer = query.writer(self.allocator);
|
||||||
|
|
||||||
|
if (self.query_params.count() == 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
_ = try writer.write("?");
|
||||||
|
var it = self.query_params.iterator();
|
||||||
|
while (it.next()) |kv| {
|
||||||
|
_ = try writer.write(kv.key_ptr.*);
|
||||||
|
_ = try writer.write("=");
|
||||||
|
_ = try writer.write(kv.value_ptr.*);
|
||||||
|
if (it.next()) |_| {
|
||||||
|
try writer.writeByte('&');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.toOwnedSlice(self.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(self: *FetchReq, comptime T: type, path: []const u8) !zjson.Owned(T) {
|
pub fn get(self: *FetchReq, comptime T: type, path: []const u8) !zjson.Owned(T) {
|
||||||
const result = try self.makeRequest(.GET, path, null);
|
const result = try self.makeRequest(.GET, path, null);
|
||||||
if (result.status != .ok)
|
if (result.status != .ok)
|
||||||
@ -207,16 +242,16 @@ pub const FetchReq = struct {
|
|||||||
to_post: ?[]const u8,
|
to_post: ?[]const u8,
|
||||||
) MakeRequestError!http.Client.FetchResult {
|
) MakeRequestError!http.Client.FetchResult {
|
||||||
var buf: [256]u8 = undefined;
|
var buf: [256]u8 = undefined;
|
||||||
const constructed = try std.fmt.bufPrint(&buf, "{s}{s}", .{ BASE_URL, path });
|
const constructed = try std.fmt.bufPrint(&buf, "{s}{s}{s}", .{ BASE_URL, path, try self.formatQueryParams() });
|
||||||
|
|
||||||
|
try self.extra_headers.append(http.Header{ .name = "Accept", .value = "application/json" });
|
||||||
|
try self.extra_headers.append(http.Header{ .name = "Content-Type", .value = "application/json" });
|
||||||
|
try self.extra_headers.append(http.Header{ .name = "Authorization", .value = self.token });
|
||||||
|
|
||||||
var fetch_options = http.Client.FetchOptions{
|
var fetch_options = http.Client.FetchOptions{
|
||||||
.location = http.Client.FetchOptions.Location{ .url = constructed },
|
.location = http.Client.FetchOptions.Location{ .url = constructed },
|
||||||
.extra_headers = &[_]http.Header{
|
|
||||||
http.Header{ .name = "Accept", .value = "application/json" },
|
|
||||||
http.Header{ .name = "Content-Type", .value = "application/json" },
|
|
||||||
http.Header{ .name = "Authorization", .value = self.token },
|
|
||||||
},
|
|
||||||
.method = method,
|
.method = method,
|
||||||
|
.extra_headers = try self.extra_headers.toOwnedSlice(),
|
||||||
.response_storage = .{ .dynamic = &self.body },
|
.response_storage = .{ .dynamic = &self.body },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -271,13 +306,14 @@ pub const FetchReq = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var uri_buf: [256]u8 = undefined;
|
var uri_buf: [256]u8 = undefined;
|
||||||
const uri = try std.Uri.parse(try std.fmt.bufPrint(&uri_buf, "{s}{s}", .{ BASE_URL, path }));
|
const uri = try std.Uri.parse(try std.fmt.bufPrint(&uri_buf, "{s}{s}{s}", .{ BASE_URL, path, try self.formatQueryParams() }));
|
||||||
|
|
||||||
var server_header_buffer: [16 * 1024]u8 = undefined;
|
var server_header_buffer: [16 * 1024]u8 = undefined;
|
||||||
var request = try self.client.open(method, uri, .{
|
var request = try self.client.open(method, uri, .{
|
||||||
.keep_alive = false,
|
.keep_alive = false,
|
||||||
.server_header_buffer = &server_header_buffer,
|
.server_header_buffer = &server_header_buffer,
|
||||||
.headers = headers,
|
.headers = headers,
|
||||||
|
.extra_headers = try self.extra_headers.toOwnedSlice(),
|
||||||
});
|
});
|
||||||
defer request.deinit();
|
defer request.deinit();
|
||||||
request.transfer_encoding = .{ .content_length = body.len };
|
request.transfer_encoding = .{ .content_length = body.len };
|
||||||
|
205
src/shard.zig
205
src/shard.zig
@ -200,7 +200,6 @@ inline fn _connect_ws(allocator: mem.Allocator, url: []const u8) !ws.Client {
|
|||||||
.host = url,
|
.host = url,
|
||||||
});
|
});
|
||||||
|
|
||||||
// maybe change this to a buffer
|
|
||||||
var buf: [0x100]u8 = undefined;
|
var buf: [0x100]u8 = undefined;
|
||||||
const host = try std.fmt.bufPrint(&buf, "host: {s}", .{url});
|
const host = try std.fmt.bufPrint(&buf, "host: {s}", .{url});
|
||||||
|
|
||||||
@ -2204,12 +2203,11 @@ pub fn leaveGuild(self: *Self, guild_id: Snowflake) RequestFailedError!void {
|
|||||||
|
|
||||||
/// Create a new DM channel with a user.
|
/// Create a new DM channel with a user.
|
||||||
/// Returns a DM channel object (if one already exists, it will be returned instead).
|
/// Returns a DM channel object (if one already exists, it will be returned instead).
|
||||||
pub fn Dm(self: *Self, whom: Snowflake) RequestFailedError!zjson.Owned(Types.Channel) {
|
pub fn dm(self: *Self, whom: Snowflake) RequestFailedError!zjson.Owned(Types.Channel) {
|
||||||
var req = FetchReq.init(self.allocator, self.details.token);
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
const dm = try req.post(Types.Channel, "/users/@me/channels", .{ .recipient_id = whom });
|
return req.post(Types.Channel, "/users/@me/channels", .{ .recipient_id = whom });
|
||||||
return dm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new group DM channel with multiple users.
|
/// Create a new group DM channel with multiple users.
|
||||||
@ -2241,3 +2239,202 @@ pub fn updateMyApplicationConnection(self: *Self) RequestFailedError!void {
|
|||||||
_ = self;
|
_ = self;
|
||||||
@panic("unimplemented\n");
|
@panic("unimplemented\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start methods for emojis
|
||||||
|
|
||||||
|
/// Returns a list of emoji objects for the given guild.
|
||||||
|
/// Includes `user` fields if the bot has the `CREATE_GUILD_EXPRESSIONS` or `MANAGE_GUILD_EXPRESSIONS` permission.
|
||||||
|
pub fn fetchEmojis(self: *Self, guild_id: Snowflake) RequestFailedError!zjson.Owned([]Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/guilds/{d}/emojis", .{guild_id.into()});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
const emojis = try req.get([]Types.Emoji, path);
|
||||||
|
return emojis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an emoji object for the given guild and emoji IDs.
|
||||||
|
/// Includes the `user` field if the bot has the `MANAGE_GUILD_EXPRESSIONS` permission, or if the bot created the emoji and has the the `CREATE_GUILD_EXPRESSIONS` permission.
|
||||||
|
pub fn fetchEmoji(self: *Self, guild_id: Snowflake, emoji_id: Snowflake) RequestFailedError!zjson.Owned(Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/guilds/{d}/emojis/{d}", .{ guild_id.into(), emoji_id.into() });
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
const emoji = try req.get(Types.Emoji, path);
|
||||||
|
return emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new emoji for the guild.
|
||||||
|
/// Requires the `CREATE_GUILD_EXPRESSIONS` permission.
|
||||||
|
/// Returns the new emoji object on success.
|
||||||
|
/// Fires a Guild Emojis Update Gateway event.
|
||||||
|
pub fn createEmoji(self: *Self, guild_id: Snowflake, emoji: Types.CreateGuildEmoji) RequestFailedError!zjson.Owned(Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/guilds/{d}/emojis", .{guild_id.into()});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
return req.post(Types.Emoji, path, emoji);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the given emoji.
|
||||||
|
/// For emojis created by the current user, requires either the `CREATE_GUILD_EXPRESSIONS` or `MANAGE_GUILD_EXPRESSIONS` permission.
|
||||||
|
/// For other emojis, requires the `MANAGE_GUILD_EXPRESSIONS` permission.
|
||||||
|
/// Returns the updated emoji object on success.
|
||||||
|
/// Fires a Guild Emojis Update Gateway event.
|
||||||
|
pub fn editEmoji(self: *Self, guild_id: Snowflake, emoji: Types.ModifyGuildEmoji) RequestFailedError!zjson.Owned(Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/guilds/{d}/emojis", .{guild_id.into()});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
return req.patch(Types.Emoji, path, emoji);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete the given emoji.
|
||||||
|
/// For emojis created by the current user, requires either the `CREATE_GUILD_EXPRESSIONS` or `MANAGE_GUILD_EXPRESSIONS` permission.
|
||||||
|
/// For other emojis, requires the `MANAGE_GUILD_EXPRESSIONS` permission.
|
||||||
|
/// Returns 204 No Content on success.
|
||||||
|
/// Fires a Guild Emojis Update Gateway event.
|
||||||
|
pub fn deleteEmoji(self: *Self, guild_id: Snowflake, emoji_id: Snowflake) RequestFailedError!zjson.Owned(Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/guilds/{d}/emojis/{d}", .{ guild_id.into(), emoji_id.into() });
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
try req.delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an object containing a list of emoji objects for the given application under the `items` key.
|
||||||
|
/// Includes a `user` object for the team member that uploaded the emoji from the app's settings, or for the bot user if uploaded using the API.
|
||||||
|
pub fn fetchApplicationEmojis(self: *Self, application_id: Snowflake) RequestFailedError!zjson.Owned([]Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/applications/{d}/emojis", .{application_id.into()});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
const emojis = try req.get([]Types.Emoji, path);
|
||||||
|
return emojis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an emoji object for the given application and emoji IDs. Includes the user field.
|
||||||
|
pub fn fetchApplicationEmoji(self: *Self, application_id: Snowflake, emoji_id: Snowflake) RequestFailedError!zjson.Owned(Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/applications/{d}/emojis/{d}", .{ application_id.into(), emoji_id.into() });
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
const emoji = try req.get(Types.Emoji, path);
|
||||||
|
return emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new emoji for the application. Returns the new emoji object on success.
|
||||||
|
pub fn createApplicationEmoji(self: *Self, application_id: Snowflake, emoji: Types.CreateGuildEmoji) RequestFailedError!zjson.Owned(Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/applications/{d}/emojis", .{application_id.into()});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
return req.post(Types.Emoji, path, emoji);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Modify the given emoji. Returns the updated emoji object on success.
|
||||||
|
pub fn editApplicationEmoji(self: *Self, application_id: Snowflake, emoji: Types.ModifyGuildEmoji) RequestFailedError!zjson.Owned(Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/applications/{d}/emojis", .{application_id.into()});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
return req.patch(Types.Emoji, path, emoji);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete the given emoji. Returns 204 No Content on success.
|
||||||
|
pub fn deleteApplicationEmoji(self: *Self, application_id: Snowflake, emoji_id: Snowflake) RequestFailedError!zjson.Owned(Types.Emoji) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/applications/{d}/emojis/{d}", .{ application_id.into(), emoji_id.into() });
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
try req.delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start invites
|
||||||
|
|
||||||
|
/// Returns an invite object for the given code.
|
||||||
|
pub fn fetchInvite(self: *Self, code: []const u8) RequestFailedError!zjson.Owned(Types.Invite) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/invites/{s}", .{code});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
return req.get(Types.Invite, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete an invite.
|
||||||
|
/// Requires the `MANAGE_CHANNELS` permission on the channel this invite belongs to, or `MANAGE_GUILD` to remove any invite across the guild.
|
||||||
|
/// Returns an invite object on success.
|
||||||
|
/// Fires an Invite Delete Gateway event.
|
||||||
|
pub fn deleteInvite(self: *Self, code: []const u8) RequestFailedError!void {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/invites/{s}", .{code});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
try req.delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll stuff
|
||||||
|
|
||||||
|
/// Get a list of users that voted for this specific answer.
|
||||||
|
pub fn fetchAnswerVoters(
|
||||||
|
self: *Self,
|
||||||
|
channel_id: Snowflake,
|
||||||
|
poll_id: Snowflake,
|
||||||
|
answer_id: Snowflake,
|
||||||
|
) RequestFailedError!zjson.Owner([]Types.User) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/channels/{d}/polls/{d}/answers/{d}", .{
|
||||||
|
channel_id.into(),
|
||||||
|
poll_id.into(),
|
||||||
|
answer_id.into(),
|
||||||
|
});
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
const voters = try req.get([]Types.User, path);
|
||||||
|
return voters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Immediately ends the poll.
|
||||||
|
/// You cannot end polls from other users.
|
||||||
|
///
|
||||||
|
/// Returns a message object. Fires a Message Update Gateway event.
|
||||||
|
pub fn endPoll(
|
||||||
|
self: *Self,
|
||||||
|
channel_id: Snowflake,
|
||||||
|
poll_id: Snowflake,
|
||||||
|
) RequestFailedError!zjson.Owned(Types.Message) {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
const path = try std.fmt.bufPrint(&buf, "/channels/{d}/polls/{d}/expire", .{ channel_id.into(), poll_id.into() });
|
||||||
|
|
||||||
|
var req = FetchReq.init(self.allocator, self.details.token);
|
||||||
|
defer req.deinit();
|
||||||
|
|
||||||
|
const msg = try req.post(Types.Message, path);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
@ -52,8 +52,8 @@ pub const Snowflake = enum(u64) {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format(self: Snowflake) ![]const u8 {
|
pub fn format(self: Snowflake, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
var buf: [256]u8 = undefined;
|
var buf: [256]u8 = undefined;
|
||||||
return std.fmt.bufPrint(&buf, "{d}\n", .{self.into()});
|
try writer.writeAll(try std.fmt.bufPrint(&buf, "{d}\n", .{self.into()}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user