diff --git a/build.zig b/build.zig index 394b544..cbdbe0d 100644 --- a/build.zig +++ b/build.zig @@ -16,7 +16,6 @@ pub fn build(b: *std.Build) void { const zlib = b.dependency("zlib", .{}); - const dzig = b.addModule("discord.zig", .{ .root_source_file = b.path("src/discord.zig"), .link_libc = true, diff --git a/src/discord.zig b/src/discord.zig index 8e90249..5fa89f1 100644 --- a/src/discord.zig +++ b/src/discord.zig @@ -366,8 +366,15 @@ pub fn CustomisedSession(comptime Table: cache.TableTemplate) type { log: Log, cache: cache.TableTemplate, }) !void { - self.token = settings.token; - var req = FetchReq.init(self.allocator, settings.token); + if (!std.mem.startsWith(u8, settings.token, "Bot")) { + var buffer = [_]u8{undefined} ** 128; + const printed = try std.fmt.bufPrint(&buffer, "Bot {s}", .{settings.token}); + self.token = printed; + } else { + self.token = settings.token; + } + + var req = FetchReq.init(self.allocator, self.token); defer req.deinit(); const res = try req.makeRequest(.GET, "/gateway/bot", null); @@ -383,7 +390,7 @@ pub fn CustomisedSession(comptime Table: cache.TableTemplate) type { defer parsed.deinit(); self.sharder = try Sharder(Table).init(self.allocator, .{ - .token = settings.token, + .token = self.token, .intents = settings.intents, .run = settings.run, .options = Sharder(Table).SessionOptions{ @@ -427,8 +434,5 @@ pub fn start(self: *Session, settings: struct { log: Log, cache: cache.TableTemplate, }) !void { - if (std.mem.startsWith(u8, settings.token, "Bot")) // save memory this way - std.debug.panic("Your token is invalid, try prepending Bot to it"); - return self.start(settings); } diff --git a/src/extra/permissions.zig b/src/extra/permissions.zig index cc46ec3..6897d46 100644 --- a/src/extra/permissions.zig +++ b/src/extra/permissions.zig @@ -1,52 +1,48 @@ const BitwisePermissionFlags = @import("../structures/shared.zig").BitwisePermissionFlags; +const IntegerBitSet = @import("std").StaticBitSet(usize); pub const Permissions = struct { - bitfield: BitwisePermissionFlags = .{}, + bitset: IntegerBitSet = .initEmpty(), + const bitfield = BitwisePermissionFlags{}; - pub fn all() BitwisePermissionFlags { - var bits: @Vector(u64, u1) = @bitCast(BitwisePermissionFlags{}); + pub const none = Permissions{}; - bits = @splat(1); - - return BitwisePermissionFlags.fromRaw(@bitCast(bits)); + pub fn all() Permissions { + return .{ .bitset = .initFull() }; } - pub fn init(bitfield: anytype) Permissions { - return Permissions{ .bitfield = @bitCast(bitfield) }; + pub fn has(self: Permissions, permission: BitwisePermissionFlags) bool { + return self.bitset.isSet(@intCast(permission)); } - pub fn has(self: Permissions, bit: u1) bool { - return (self.bitfield & bit) == bit; + pub fn missing(self: Permissions, permission: BitwisePermissionFlags) bool { + return !self.bitset.isSet(@intCast(permission)); } - pub fn missing(self: Permissions, bit: u1) bool { - return (self.bitfield & bit) == 0; + pub fn isAdmin(self: Permissions) bool { + return self.bitset.isSet(@intCast(BitwisePermissionFlags.ADMIN)); } - pub fn equals(self: Permissions, other: anytype) bool { - return self.bitfield == Permissions.init(other).bitfield; + pub fn set(self: Permissions, permission: BitwisePermissionFlags) void { + self.bitset.set(@intCast(permission)); } - pub fn add(self: Permissions, bit: u1) void { - self.bitfield |= bit; + pub fn eql(self: Permissions, other: Permissions) bool { + return self.bitset.eql(other.bitset); } - pub fn remove(self: Permissions, bit: u1) void { - self.bitfield &= ~bit; - } - - pub fn has2(self: Permissions, bit: u1) bool { - const administrator = BitwisePermissionFlags{ .ADMINISTRATOR = true }; - return self.has(bit) or (self.bitfield & administrator) == administrator; + pub fn any(self: Permissions, other: Permissions) bool { + return self.bitset.supersetOf(other.bitset); } pub fn toRaw(self: Permissions) u64 { - return @bitCast(self.bitfield); + return @intCast(self.bitset.mask); } pub fn fromRaw(raw: u64) Permissions { - return Permissions{ .bitfield = @bitCast(raw) }; + return .{ .bitset = .{ .mask = raw } }; } + /// std.json stringify pub fn jsonStringify(permissions: Permissions, writer: anytype) !void { try writer.print("", .{permissions.toRaw()}); @@ -63,3 +59,56 @@ test { testing.expectEqual(all_permissions.toRaw(), ALL); } + +test "is admin and set works" { + var permissions = Permissions.none; + permissions.set(Permissions.bitfield.ADMINISTRATOR); + testing.expect(permissions.isAdmin()); +} + +test "eql works" { + var permissions1 = Permissions.none; + var permissions2 = Permissions.none; + permissions1.set(Permissions.bitfield.ADMINISTRATOR); + permissions2.set(Permissions.bitfield.ADMINISTRATOR); + testing.expect(permissions1.eql(permissions2)); +} + +test "has permission" { + var permissions = Permissions.none; + permissions.set(Permissions.bitfield.ADMINISTRATOR); + testing.expect(permissions.has(Permissions.bitfield.ADMINISTRATOR)); + testing.expect(!permissions.has(Permissions.bitfield.MANAGE_ROLES)); +} + +test "missing permission" { + var permissions = Permissions.none; + permissions.set(Permissions.bitfield.ADMINISTRATOR); + testing.expect(!permissions.missing(Permissions.bitfield.ADMINISTRATOR)); + testing.expect(permissions.missing(Permissions.bitfield.MANAGE_ROLES)); +} + +test "missing multiple permissions" { + var permissions1 = Permissions.none; + permissions1.set(Permissions.bitfield.KICK_MEMBERS); // only has kick members + + var permissions2 = Permissions.none; // to check + permissions2.set(Permissions.bitfield.BAN_MEMBERS); + permissions2.set(Permissions.bitfield.KICK_MEMBERS); + + // has both permissions + testing.expect(permissions1.missing(permissions2)); +} + +test "any permissions" { + var permissions1 = Permissions.none; + var permissions2 = Permissions.none; + permissions1.set(Permissions.bitfield.ADMINISTRATOR); + permissions2.set(Permissions.bitfield.MANAGE_GUILD); + + testing.expect(!permissions1.any(permissions2)); + + permissions2.set(Permissions.bitfield.MANAGE_GUILD); + + testing.expect(permissions1.any(permissions2)); +} diff --git a/src/shard.zig b/src/shard.zig index db00037..9978ab4 100644 --- a/src/shard.zig +++ b/src/shard.zig @@ -2906,5 +2906,7 @@ pub fn Shard(comptime Table: TableTemplate) type { inline fn logif(self: *Self, comptime format: []const u8, args: anytype) void { internalLogif(self.log, format, args); } + + }; } diff --git a/test/test.zig b/test/test.zig index 6224626..77e7b93 100644 --- a/test/test.zig +++ b/test/test.zig @@ -46,8 +46,16 @@ pub fn main() !void { var handler = Discord.init(allocator); defer handler.deinit(); + const env_map = try allocator.create(std.process.EnvMap); + env_map.* = try std.process.getEnvMap(allocator); + defer env_map.deinit(); + + const token = env_map.get("DISCORD_TOKEN") orelse { + @panic("DISCORD_TOKEN not found in environment variables"); + }; + try handler.start(.{ - .token = std.posix.getenv("DISCORD_TOKEN").?, + .token = token, .intents = Intents.fromRaw(INTENTS), .run = .{ .message_create = &message_create, .ready = &ready }, .log = .yes,