mirror of
https://github.com/discordeno/discordeno.git
synced 2026-09-17 08:47:22 +00:00
bettrrrr
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { startBot } from "./src/bot.ts";
|
||||
|
||||
startBot({
|
||||
token: "Nzg1MTM3Mjg5MDcyMDgyOTY1.X8zeFA.vP6lAmWqO2wy9-uOyV4__wNMy8o",
|
||||
intents: ["GUILDS", "GUILD_MESSAGES", "GUILD_EMOJIS"],
|
||||
eventHandlers: {
|
||||
ready() {
|
||||
console.log("Successfully connected to gateway");
|
||||
},
|
||||
messageCreate(message) {
|
||||
if (message.content === "ping") {
|
||||
message.reply("Pong using Discordeno!");
|
||||
}
|
||||
},
|
||||
guildEmojisUpdate(g, e, c) {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,421 @@
|
||||
/**
|
||||
* Custom implementation of a double ended queue.
|
||||
*/
|
||||
export class Denque<T> {
|
||||
#head = 0;
|
||||
#tail = 0;
|
||||
#capacity?: number = undefined;
|
||||
#capacityMask = 0x3;
|
||||
#list = new Array(4);
|
||||
|
||||
constructor(array?: T[], options?: IDenqueOptions) {
|
||||
if (options?.capacity) this.#capacity = options.capacity;
|
||||
|
||||
if (Array.isArray(array)) {
|
||||
this.fromArray(array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item at the specified index from the list.
|
||||
* 0 is the first element, 1 is the second, and so on...
|
||||
* Elements at negative values are that many from the end: -1 is one before the end
|
||||
* (the last element), -2 is two before the end (one before last), etc.
|
||||
*/
|
||||
peekAt(index: number) {
|
||||
let i = index;
|
||||
// expect a number or return undefined
|
||||
if (i !== (i | 0)) {
|
||||
return void 0;
|
||||
}
|
||||
let len = this.size();
|
||||
if (i >= len || i < -len) return undefined;
|
||||
if (i < 0) i += len;
|
||||
i = (this.#head + i) & this.#capacityMask;
|
||||
return this.#list[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for peekAt()
|
||||
*/
|
||||
get(i: number) {
|
||||
return this.peekAt(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first item in the list without removing it.
|
||||
*/
|
||||
peek() {
|
||||
if (this.#head === this.#tail) return undefined;
|
||||
return this.#list[this.#head];
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for peek()
|
||||
*/
|
||||
peekFront() {
|
||||
return this.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item that is at the back of the queue without removing it.
|
||||
* Uses peekAt(-1)
|
||||
*/
|
||||
peekBack() {
|
||||
return this.peekAt(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current length of the queue
|
||||
*/
|
||||
get length() {
|
||||
return this.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of items on the list, or 0 if empty.
|
||||
*/
|
||||
size() {
|
||||
if (this.#head === this.#tail) return 0;
|
||||
if (this.#head < this.#tail) return this.#tail - this.#head;
|
||||
else return this.#capacityMask + 1 - (this.#head - this.#tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item at the beginning of the list.
|
||||
*/
|
||||
unshift(item: T) {
|
||||
if (item === undefined) return this.size();
|
||||
let len = this.#list.length;
|
||||
this.#head = (this.#head - 1 + len) & this.#capacityMask;
|
||||
this.#list[this.#head] = item;
|
||||
if (this.#tail === this.#head) this.growArray();
|
||||
if (this.#capacity && this.size() > this.#capacity) this.pop();
|
||||
if (this.#head < this.#tail) return this.#tail - this.#head;
|
||||
else return this.#capacityMask + 1 - (this.#head - this.#tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and return the first item on the list,
|
||||
* Returns undefined if the list is empty.
|
||||
|
||||
*/
|
||||
shift() {
|
||||
let head = this.#head;
|
||||
if (head === this.#tail) return undefined;
|
||||
let item = this.#list[head];
|
||||
this.#list[head] = undefined;
|
||||
this.#head = (head + 1) & this.#capacityMask;
|
||||
if (
|
||||
head < 2 && this.#tail > 10000 && this.#tail <= this.#list.length >>> 2
|
||||
) {
|
||||
this.shrinkArray();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to the bottom of the list.
|
||||
*/
|
||||
push(item: T) {
|
||||
if (item === undefined) return this.size();
|
||||
let tail = this.#tail;
|
||||
this.#list[tail] = item;
|
||||
this.#tail = (tail + 1) & this.#capacityMask;
|
||||
if (this.#tail === this.#head) {
|
||||
this.growArray();
|
||||
}
|
||||
if (this.#capacity && this.size() > this.#capacity) {
|
||||
this.shift();
|
||||
}
|
||||
if (this.#head < this.#tail) return this.#tail - this.#head;
|
||||
else return this.#capacityMask + 1 - (this.#head - this.#tail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and return the last item on the list.
|
||||
* Returns undefined if the list is empty.
|
||||
*/
|
||||
pop() {
|
||||
let tail = this.#tail;
|
||||
if (tail === this.#head) return undefined;
|
||||
let len = this.#list.length;
|
||||
this.#tail = (tail - 1 + len) & this.#capacityMask;
|
||||
let item = this.#list[this.#tail];
|
||||
this.#list[this.#tail] = undefined;
|
||||
if (this.#head < 2 && tail > 10000 && tail <= len >>> 2) this.shrinkArray();
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and return the item at the specified index from the list.
|
||||
* Returns undefined if the list is empty.
|
||||
*/
|
||||
removeOne(index: number) {
|
||||
let i = index;
|
||||
// expect a number or return undefined
|
||||
if (i !== (i | 0)) {
|
||||
return void 0;
|
||||
}
|
||||
if (this.#head === this.#tail) return void 0;
|
||||
let size = this.size();
|
||||
let len = this.#list.length;
|
||||
if (i >= size || i < -size) return void 0;
|
||||
if (i < 0) i += size;
|
||||
i = (this.#head + i) & this.#capacityMask;
|
||||
let item = this.#list[i];
|
||||
let k;
|
||||
if (index < size / 2) {
|
||||
for (k = index; k > 0; k--) {
|
||||
this.#list[i] = this.#list[(i = (i - 1 + len) & this.#capacityMask)];
|
||||
}
|
||||
this.#list[i] = void 0;
|
||||
this.#head = (this.#head + 1 + len) & this.#capacityMask;
|
||||
} else {
|
||||
for (k = size - 1 - index; k > 0; k--) {
|
||||
this.#list[i] = this.#list[(i = (i + 1 + len) & this.#capacityMask)];
|
||||
}
|
||||
this.#list[i] = void 0;
|
||||
this.#tail = (this.#tail - 1 + len) & this.#capacityMask;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove number of items from the specified index from the list.
|
||||
* Returns array of removed items.
|
||||
* Returns undefined if the list is empty.
|
||||
*/
|
||||
remove(index: number, count: number) {
|
||||
let i = index;
|
||||
let removed;
|
||||
let del_count = count;
|
||||
// expect a number or return undefined
|
||||
if (i !== (i | 0)) {
|
||||
return void 0;
|
||||
}
|
||||
if (this.#head === this.#tail) return void 0;
|
||||
let size = this.size();
|
||||
let len = this.#list.length;
|
||||
if (i >= size || i < -size || count < 1) return void 0;
|
||||
if (i < 0) i += size;
|
||||
if (count === 1 || !count) {
|
||||
removed = new Array(1);
|
||||
removed[0] = this.removeOne(i);
|
||||
return removed;
|
||||
}
|
||||
if (i === 0 && i + count >= size) {
|
||||
removed = this.toArray();
|
||||
this.clear();
|
||||
return removed;
|
||||
}
|
||||
if (i + count > size) count = size - i;
|
||||
let k;
|
||||
removed = new Array(count);
|
||||
for (k = 0; k < count; k++) {
|
||||
removed[k] = this.#list[(this.#head + i + k) & this.#capacityMask];
|
||||
}
|
||||
i = (this.#head + i) & this.#capacityMask;
|
||||
if (index + count === size) {
|
||||
this.#tail = (this.#tail - count + len) & this.#capacityMask;
|
||||
for (k = count; k > 0; k--) {
|
||||
this.#list[(i = (i + 1 + len) & this.#capacityMask)] = void 0;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
if (index === 0) {
|
||||
this.#head = (this.#head + count + len) & this.#capacityMask;
|
||||
for (k = count - 1; k > 0; k--) {
|
||||
this.#list[(i = (i + 1 + len) & this.#capacityMask)] = void 0;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
if (i < size / 2) {
|
||||
this.#head = (this.#head + index + count + len) & this.#capacityMask;
|
||||
for (k = index; k > 0; k--) {
|
||||
this.unshift(this.#list[(i = (i - 1 + len) & this.#capacityMask)]);
|
||||
}
|
||||
i = (this.#head - 1 + len) & this.#capacityMask;
|
||||
while (del_count > 0) {
|
||||
this.#list[(i = (i - 1 + len) & this.#capacityMask)] = void 0;
|
||||
del_count--;
|
||||
}
|
||||
if (index < 0) this.#tail = i;
|
||||
} else {
|
||||
this.#tail = i;
|
||||
i = (i + count + len) & this.#capacityMask;
|
||||
for (k = size - (count + index); k > 0; k--) {
|
||||
this.push(this.#list[i++]);
|
||||
}
|
||||
i = this.#tail;
|
||||
while (del_count > 0) {
|
||||
this.#list[(i = (i + 1 + len) & this.#capacityMask)] = void 0;
|
||||
del_count--;
|
||||
}
|
||||
}
|
||||
if (this.#head < 2 && this.#tail > 10000 && this.#tail <= len >>> 2) {
|
||||
this.shrinkArray();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Native splice implementation.
|
||||
* Remove number of items from the specified index from the list and/or add new elements.
|
||||
* Returns array of removed items or empty array if count == 0.
|
||||
* Returns undefined if the list is empty.
|
||||
*/
|
||||
splice(index: number, count: number) {
|
||||
let i = index;
|
||||
// expect a number or return undefined
|
||||
if (i !== (i | 0)) {
|
||||
return void 0;
|
||||
}
|
||||
let size = this.size();
|
||||
if (i < 0) i += size;
|
||||
if (i > size) return void 0;
|
||||
if (arguments.length > 2) {
|
||||
let k;
|
||||
let temp;
|
||||
let removed;
|
||||
let arg_len = arguments.length;
|
||||
let len = this.#list.length;
|
||||
let arguments_index = 2;
|
||||
if (!size || i < size / 2) {
|
||||
temp = new Array(i);
|
||||
for (k = 0; k < i; k++) {
|
||||
temp[k] = this.#list[(this.#head + k) & this.#capacityMask];
|
||||
}
|
||||
if (count === 0) {
|
||||
removed = [];
|
||||
if (i > 0) {
|
||||
this.#head = (this.#head + i + len) & this.#capacityMask;
|
||||
}
|
||||
} else {
|
||||
removed = this.remove(i, count);
|
||||
this.#head = (this.#head + i + len) & this.#capacityMask;
|
||||
}
|
||||
while (arg_len > arguments_index) {
|
||||
this.unshift(arguments[--arg_len]);
|
||||
}
|
||||
for (k = i; k > 0; k--) {
|
||||
this.unshift(temp[k - 1]);
|
||||
}
|
||||
} else {
|
||||
temp = new Array(size - (i + count));
|
||||
let leng = temp.length;
|
||||
for (k = 0; k < leng; k++) {
|
||||
temp[k] =
|
||||
this.#list[(this.#head + i + count + k) & this.#capacityMask];
|
||||
}
|
||||
if (count === 0) {
|
||||
removed = [];
|
||||
if (i != size) {
|
||||
this.#tail = (this.#head + i + len) & this.#capacityMask;
|
||||
}
|
||||
} else {
|
||||
removed = this.remove(i, count);
|
||||
this.#tail = (this.#tail - leng + len) & this.#capacityMask;
|
||||
}
|
||||
while (arguments_index < arg_len) {
|
||||
this.push(arguments[arguments_index++]);
|
||||
}
|
||||
for (k = 0; k < leng; k++) {
|
||||
this.push(temp[k]);
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
} else {
|
||||
return this.remove(i, count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft clear - does not reset capacity.
|
||||
*/
|
||||
clear() {
|
||||
this.#head = 0;
|
||||
this.#tail = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true or false whether the list is empty.
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.#head === this.#tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all queue items.
|
||||
*/
|
||||
toArray() {
|
||||
return this.copyArray(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* -------------
|
||||
* INTERNALS
|
||||
* -------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fills the queue with items from an array
|
||||
* For use in the constructor
|
||||
*/
|
||||
private fromArray(array: T[]) {
|
||||
for (var i = 0; i < array.length; i++) this.push(array[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the array either fully or partially
|
||||
*/
|
||||
private copyArray(fullCopy: boolean) {
|
||||
let newArray = [];
|
||||
let list = this.#list;
|
||||
let len = list.length;
|
||||
let i;
|
||||
if (fullCopy || this.#head > this.#tail) {
|
||||
for (i = this.#head; i < len; i++) newArray.push(list[i]);
|
||||
for (i = 0; i < this.#tail; i++) newArray.push(list[i]);
|
||||
} else {
|
||||
for (i = this.#head; i < this.#tail; i++) newArray.push(list[i]);
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grows the internal list array.
|
||||
*/
|
||||
private growArray() {
|
||||
if (this.#head) {
|
||||
// copy existing data, head to end, then beginning to tail.
|
||||
this.#list = this.copyArray(true);
|
||||
this.#head = 0;
|
||||
}
|
||||
|
||||
// head is at 0 and array is now full, safe to extend
|
||||
this.#tail = this.#list.length;
|
||||
|
||||
this.#list.length *= 2;
|
||||
this.#capacityMask = (this.#capacityMask << 1) | 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shrinks the internal list array.
|
||||
*/
|
||||
shrinkArray() {
|
||||
console.log("list", this.#list.length);
|
||||
this.#list.length >>>= 1;
|
||||
console.log("mask", this.#capacityMask);
|
||||
this.#capacityMask >>>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IDenqueOptions {
|
||||
capacity?: number;
|
||||
}
|
||||
|
||||
const f = new Denque(["a", "b", "c", "a", "d"]);
|
||||
console.log(f.toArray());
|
||||
console.log(f.removeOne(1));
|
||||
console.log(f.toArray());
|
||||
+80
-57
@@ -1,23 +1,48 @@
|
||||
import { cacheHandlers } from "../api/controllers/cache.ts";
|
||||
import { Role } from "../api/structures/mod.ts";
|
||||
import { Channel, Guild, Member, Role } from "../api/structures/mod.ts";
|
||||
import { botID } from "../bot.ts";
|
||||
import { Errors, Permission, Permissions } from "../types/mod.ts";
|
||||
|
||||
async function getCached(table: "guild", key: string | Guild): Promise<Guild>;
|
||||
async function getCached(
|
||||
table: "channel",
|
||||
key: string | Channel,
|
||||
): Promise<Channel>;
|
||||
async function getCached(
|
||||
table: "member",
|
||||
key: string | Member,
|
||||
): Promise<Member>;
|
||||
async function getCached(
|
||||
table: "guild" | "channel" | "member",
|
||||
key: string | Guild | Channel | Member,
|
||||
) {
|
||||
const cached = typeof key === "string"
|
||||
? // @ts-ignore -
|
||||
(await cacheHandlers.get(`${table}s`, key))
|
||||
: key;
|
||||
if (!cached || typeof cached === "string") {
|
||||
throw new Error(Errors[`${table.toUpperCase}_NOT_FOUND` as Errors]);
|
||||
}
|
||||
|
||||
return cached;
|
||||
}
|
||||
|
||||
/** Calculates the permissions this member has in the given guild */
|
||||
export async function calculateBasePermissions(
|
||||
memberID: string,
|
||||
guildID: string
|
||||
guild: string | Guild,
|
||||
member: string | Member,
|
||||
) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
|
||||
const member = await cacheHandlers.get("members", memberID);
|
||||
if (!member) throw new Error(Errors.MEMBER_NOT_FOUND);
|
||||
console.log(guild, await cacheHandlers.get("guilds", "800080308921696296"));
|
||||
console.log(guild);
|
||||
guild = await getCached("guild", guild);
|
||||
console.log(guild);
|
||||
member = await getCached("member", member);
|
||||
console.log(member);
|
||||
|
||||
let permissions = 0n;
|
||||
// Calculate the role permissions bits, @everyone role is not in memberRoleIDs so we need to pass guildID manualy
|
||||
permissions |= [...(member.guilds.get(guildID)?.roles || []), guildID]
|
||||
.map((id) => guild.roles.get(id)?.permissions)
|
||||
permissions |= [...(member.guilds.get(guild.id)?.roles || []), guild.id]
|
||||
.map((id) => (guild as Guild).roles.get(id)?.permissions)
|
||||
// Removes any edge case undefined
|
||||
.filter((id) => id)
|
||||
.reduce((bits, perms) => {
|
||||
@@ -26,33 +51,31 @@ export async function calculateBasePermissions(
|
||||
}, 0n);
|
||||
|
||||
// If the memberID is equal to the guild ownerID he automatically has every permission so we add ADMINISTRATOR permission
|
||||
if (guild.ownerID === memberID) permissions |= 8n;
|
||||
if (guild.ownerID === member.id) permissions |= 8n;
|
||||
// Return the members permission bits as a string
|
||||
return permissions.toString();
|
||||
}
|
||||
|
||||
/** Calculates the permissions this member has for the given Channel */
|
||||
export async function calculateChannelOverwrites(
|
||||
memberID: string,
|
||||
channelID: string
|
||||
channel: string | Channel,
|
||||
member: string | Member,
|
||||
) {
|
||||
const channel = await cacheHandlers.get("channels", channelID);
|
||||
if (!channel) throw new Error(Errors.CHANNEL_NOT_FOUND);
|
||||
channel = await getCached("channel", channel);
|
||||
|
||||
// This is a DM channel so return ADMINISTRATOR permission
|
||||
if (!channel.guildID) return "8";
|
||||
|
||||
member = await getCached("member", member);
|
||||
|
||||
// Get all the role permissions this member already has
|
||||
let permissions = BigInt(
|
||||
await calculateBasePermissions(memberID, channel.guildID)
|
||||
await calculateBasePermissions(channel.guildID, member),
|
||||
);
|
||||
|
||||
const member = await cacheHandlers.get("members", memberID);
|
||||
if (!member) throw new Error(Errors.MEMBER_NOT_FOUND);
|
||||
|
||||
// First calculate @everyone overwrites since these have the lowest priority
|
||||
const overwriteEveryone = channel?.permissionOverwrites.find(
|
||||
(overwrite) => overwrite.id === channel.guildID
|
||||
(overwrite) => overwrite.id === (channel as Channel).guildID,
|
||||
);
|
||||
if (overwriteEveryone) {
|
||||
// First remove denied permissions since denied < allowed
|
||||
@@ -79,7 +102,7 @@ export async function calculateChannelOverwrites(
|
||||
|
||||
// Third calculate member specific overwrites since these have the highest priority
|
||||
const overwriteMember = overwrites.find(
|
||||
(overwrite) => overwrite.id === memberID
|
||||
(overwrite) => overwrite.id === (member as Member).id,
|
||||
);
|
||||
if (overwriteMember) {
|
||||
permissions &= ~BigInt(overwriteMember.deny);
|
||||
@@ -92,25 +115,25 @@ export async function calculateChannelOverwrites(
|
||||
/** Checks if the given permission bits are matching the given permissions. `ADMINISTRATOR` always returns `true` */
|
||||
export function validatePermissions(
|
||||
permissionBits: string,
|
||||
permissions: Permission[]
|
||||
permissions: Permission[],
|
||||
) {
|
||||
if (BigInt(permissionBits) & 8n) return true;
|
||||
|
||||
return permissions.every(
|
||||
(permission) =>
|
||||
// Check if permission is in permissionBits
|
||||
BigInt(permissionBits) & BigInt(Permissions[permission])
|
||||
BigInt(permissionBits) & BigInt(Permissions[permission]),
|
||||
);
|
||||
}
|
||||
|
||||
/** Checks if the given member has these permissions in the given guild */
|
||||
export async function hasGuildPermissions(
|
||||
memberID: string,
|
||||
guildID: string,
|
||||
permissions: Permission[]
|
||||
memberID: string,
|
||||
permissions: Permission[],
|
||||
) {
|
||||
// First we need the role permission bits this member has
|
||||
const basePermissions = await calculateBasePermissions(memberID, guildID);
|
||||
const basePermissions = await calculateBasePermissions(guildID, memberID);
|
||||
// Second use the validatePermissions function to check if the member has every permission
|
||||
return validatePermissions(basePermissions, permissions);
|
||||
}
|
||||
@@ -118,7 +141,7 @@ export async function hasGuildPermissions(
|
||||
/** Checks if the bot has these permissions in the given guild */
|
||||
export function botHasGuildPermissions(
|
||||
guildID: string,
|
||||
permissions: Permission[]
|
||||
permissions: Permission[],
|
||||
) {
|
||||
// Since Bot is a normal member we can use the hasRolePermissions() function
|
||||
return hasGuildPermissions(botID, guildID, permissions);
|
||||
@@ -126,14 +149,14 @@ export function botHasGuildPermissions(
|
||||
|
||||
/** Checks if the given member has these permissions for the given channel */
|
||||
export async function hasChannelPermissions(
|
||||
memberID: string,
|
||||
channelID: string,
|
||||
permissions: Permission[]
|
||||
memberID: string,
|
||||
permissions: Permission[],
|
||||
) {
|
||||
// First we need the overwrite bits this member has
|
||||
const channelOverwrites = await calculateChannelOverwrites(
|
||||
memberID,
|
||||
channelID
|
||||
channelID,
|
||||
);
|
||||
// Second use the validatePermissions function to check if the member has every permission
|
||||
return validatePermissions(channelOverwrites, permissions);
|
||||
@@ -142,7 +165,7 @@ export async function hasChannelPermissions(
|
||||
/** Checks if the bot has these permissions f0r the given channel */
|
||||
export function botHasChannelPermissions(
|
||||
channelID: string,
|
||||
permissions: Permission[]
|
||||
permissions: Permission[],
|
||||
) {
|
||||
// Since Bot is a normal member we can use the hasRolePermissions() function
|
||||
return hasChannelPermissions(botID, channelID, permissions);
|
||||
@@ -151,23 +174,23 @@ export function botHasChannelPermissions(
|
||||
/** Returns the permissions that are not in the given permissionBits */
|
||||
export function missingPermissions(
|
||||
permissionBits: string,
|
||||
permissions: Permission[]
|
||||
permissions: Permission[],
|
||||
) {
|
||||
if (BigInt(permissionBits) & 8n) return [];
|
||||
|
||||
return permissions.filter(
|
||||
(permission) => !(BigInt(permissionBits) & BigInt(Permissions[permission]))
|
||||
(permission) => !(BigInt(permissionBits) & BigInt(Permissions[permission])),
|
||||
);
|
||||
}
|
||||
|
||||
/** Throws an error if this member has not all of the given permissions */
|
||||
export async function requireGuildPermissions(
|
||||
memberID: string,
|
||||
guildID: string,
|
||||
permissions: Permission[]
|
||||
memberID: string,
|
||||
permissions: Permission[],
|
||||
) {
|
||||
// First we need the role permissions bits this member has
|
||||
const permissionBits = await calculateBasePermissions(memberID, guildID);
|
||||
const permissionBits = await calculateBasePermissions(guildID, memberID);
|
||||
// Second check if the member is missing any permissions
|
||||
const missing = missingPermissions(permissionBits, permissions);
|
||||
if (missing.length) {
|
||||
@@ -179,7 +202,7 @@ export async function requireGuildPermissions(
|
||||
/** Throws an error if the bot does not have all permissions */
|
||||
export function requireBotGuildPermissions(
|
||||
guildID: string,
|
||||
permissions: Permission[]
|
||||
permissions: Permission[],
|
||||
) {
|
||||
// Since Bot is a normal member we can use the throwOnMissingGuildPermission() function
|
||||
return requireGuildPermissions(botID, guildID, permissions);
|
||||
@@ -187,9 +210,9 @@ export function requireBotGuildPermissions(
|
||||
|
||||
/** Throws an error if this member has not all of the given permissions */
|
||||
export async function requireChannelPermissions(
|
||||
memberID: string,
|
||||
channelID: string,
|
||||
permissions: Permission[]
|
||||
memberID: string,
|
||||
permissions: Permission[],
|
||||
) {
|
||||
// First we need the channel overwrite bits this member has
|
||||
const permissionBits = await calculateChannelOverwrites(memberID, channelID);
|
||||
@@ -204,7 +227,7 @@ export async function requireChannelPermissions(
|
||||
/** Throws an error if the bot has not all of the given channel permissions */
|
||||
export function requireBotChannelPermissions(
|
||||
channelID: string,
|
||||
permissions: Permission[]
|
||||
permissions: Permission[],
|
||||
) {
|
||||
// Since Bot is a normal member we can use the throwOnMissingChannelPermission() function
|
||||
return requireChannelPermissions(botID, channelID, permissions);
|
||||
@@ -226,23 +249,25 @@ export function calculateBits(permissions: Permission[]) {
|
||||
.reduce(
|
||||
// Get the bit value for this permission and assign it to bits
|
||||
(bits, perm) => (bits |= BigInt(Permissions[perm])),
|
||||
0n
|
||||
0n,
|
||||
)
|
||||
.toString();
|
||||
}
|
||||
|
||||
// TODO: move memberID to first position
|
||||
/** Gets the highest role from the member in this guild */
|
||||
export async function highestRole(guildID: string, memberID: string) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
export async function highestRole(
|
||||
guild: string | Guild,
|
||||
member: string | Member,
|
||||
) {
|
||||
guild = await getCached("guild", guild);
|
||||
|
||||
// Get the roles from the member
|
||||
const memberRoles = (
|
||||
await cacheHandlers.get("members", memberID)
|
||||
)?.guilds.get(guildID)?.roles;
|
||||
await getCached("member", member)
|
||||
).guilds.get(guild.id)?.roles;
|
||||
// This member has no roles so the highest one is the @everyone role
|
||||
if (!memberRoles) return guild.roles.get(guildID) as Role;
|
||||
if (!memberRoles) return guild.roles.get(guild.id) as Role;
|
||||
|
||||
let memberHighestRole: Role | undefined;
|
||||
|
||||
@@ -268,12 +293,11 @@ export async function highestRole(guildID: string, memberID: string) {
|
||||
|
||||
/** Checks if the first role is higher than the second role */
|
||||
export async function higherRolePosition(
|
||||
guildID: string,
|
||||
guild: string | Guild,
|
||||
roleID: string,
|
||||
otherRoleID: string
|
||||
otherRoleID: string,
|
||||
) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
guild = await getCached("guild", guild);
|
||||
|
||||
const role = guild.roles.get(roleID);
|
||||
const otherRole = guild.roles.get(otherRoleID);
|
||||
@@ -289,15 +313,14 @@ export async function higherRolePosition(
|
||||
|
||||
/** Checks if the member has a higher position than the given role */
|
||||
export async function isHigherPosition(
|
||||
guildID: string,
|
||||
guild: string | Guild,
|
||||
memberID: string,
|
||||
compareRoleID: string
|
||||
compareRoleID: string,
|
||||
) {
|
||||
const guild = await cacheHandlers.get("guilds", guildID);
|
||||
if (!guild) throw new Error(Errors.GUILD_NOT_FOUND);
|
||||
guild = await getCached("guild", guild);
|
||||
|
||||
if (guild.ownerID === memberID) return true;
|
||||
|
||||
const memberHighestRole = await highestRole(guildID, memberID);
|
||||
return higherRolePosition(guildID, memberHighestRole.id, compareRoleID);
|
||||
const memberHighestRole = await highestRole(guild.id, memberID);
|
||||
return higherRolePosition(guild.id, memberHighestRole.id, compareRoleID);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,502 @@
|
||||
/** // deno-lint-ignore-file */
|
||||
/** Allows easy way to add a prop to a base object when needing to use complicated getters solution. */
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export function createNewProp(value: any): Partial<PropertyDescriptor> {
|
||||
return { configurable: true, enumerable: true, writable: true, value };
|
||||
}
|
||||
|
||||
interface IDenqueOptions {
|
||||
capacity?: number;
|
||||
}
|
||||
|
||||
interface Denque<T> {
|
||||
/**
|
||||
* Return the number of items on the list, or 0 if empty.
|
||||
* @returns {number}
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* Add an item to the bottom of the list.
|
||||
* @param item
|
||||
*/
|
||||
push(item: T): number;
|
||||
/**
|
||||
* Add an item at the beginning of the list.
|
||||
* @param item
|
||||
*/
|
||||
unshift(item: T): number;
|
||||
/**
|
||||
* Remove and return the last item on the list.
|
||||
* Returns undefined if the list is empty.
|
||||
* @returns {*}
|
||||
*/
|
||||
pop(): T | undefined;
|
||||
removeBack(): T | undefined;
|
||||
/**
|
||||
* Remove and return the first item on the list,
|
||||
* Returns undefined if the list is empty.
|
||||
* @returns {*}
|
||||
*/
|
||||
shift(): T | undefined;
|
||||
/**
|
||||
* Returns the item that is at the back of the queue without removing it.
|
||||
* Uses peekAt(-1)
|
||||
*/
|
||||
peekBack: T | undefined;
|
||||
/**
|
||||
* Alias for peek()
|
||||
* @returns {*}
|
||||
*/
|
||||
peekFront: T | undefined;
|
||||
/**
|
||||
* Returns the item at the specified index from the list.
|
||||
* 0 is the first element, 1 is the second, and so on...
|
||||
* Elements at negative values are that many from the end: -1 is one before the end
|
||||
* (the last element), -2 is two before the end (one before last), etc.
|
||||
* @param index
|
||||
* @returns {*}
|
||||
*/
|
||||
peekAt(index: number): T | undefined;
|
||||
/**
|
||||
* Returns the first item in the list without removing it.
|
||||
*/
|
||||
peek: T;
|
||||
/**
|
||||
* Alias for peekAt()
|
||||
* @param i
|
||||
* @returns {*}
|
||||
*/
|
||||
get(index: number): T | undefined;
|
||||
/**
|
||||
* Remove number of items from the specified index from the list.
|
||||
* Returns array of removed items.
|
||||
* Returns undefined if the list is empty.
|
||||
* @param index
|
||||
* @param count
|
||||
* @returns {array}
|
||||
*/
|
||||
remove(index: number, count: number): T[] | any;
|
||||
/**
|
||||
* Remove and return the item at the specified index from the list.
|
||||
* Returns undefined if the list is empty.
|
||||
* @param index
|
||||
* @returns {*}
|
||||
*/
|
||||
removeOne(index: number): T | undefined;
|
||||
/**
|
||||
* Native splice implementation.
|
||||
* Remove number of items from the specified index from the list and/or add new elements.
|
||||
* Returns array of removed items or empty array if count == 0.
|
||||
* Returns undefined if the list is empty.
|
||||
*
|
||||
* @param index
|
||||
* @param count
|
||||
* @param {...*} [elements]
|
||||
* @returns {array}
|
||||
*/
|
||||
splice(index: number, count: number, ...item: T[]): T[] | undefined;
|
||||
/**
|
||||
* Returns true or false whether the list is empty.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEmpty: boolean;
|
||||
/**
|
||||
* Soft clear - does not reset capacity.
|
||||
*/
|
||||
clear(): void;
|
||||
|
||||
toString(): string;
|
||||
toArray(): T[];
|
||||
|
||||
/**
|
||||
* Returns the current length of the queue
|
||||
* @return {Number}
|
||||
*/
|
||||
length: number;
|
||||
|
||||
_head: number;
|
||||
_tail: number;
|
||||
_capacity: number;
|
||||
_capacityMask: number;
|
||||
_list: T[];
|
||||
|
||||
/**
|
||||
* Fills the queue with items from an array
|
||||
* For use in the constructor
|
||||
* @param array
|
||||
* @private
|
||||
*/
|
||||
_fromArray(array: T[]): void;
|
||||
/**
|
||||
*
|
||||
* @param fullCopy
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
_copyArray(fullCopy: boolean): T[];
|
||||
/**
|
||||
* Grows the internal list array.
|
||||
* @private
|
||||
*/
|
||||
_growArray(): void;
|
||||
/**
|
||||
* Shrinks the internal list array.
|
||||
* @private
|
||||
*/
|
||||
_shrinkArray(): void;
|
||||
}
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const baseDenque: Partial<Denque<any>> = {
|
||||
peekAt(index) {
|
||||
// expect a number or return undefined
|
||||
if (index !== (index | 0)) {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
if (index >= this.size! || index < this.size!) return undefined;
|
||||
|
||||
if (index < 0) index += this.size!;
|
||||
index = (this._head! + index) & this._capacityMask!;
|
||||
|
||||
return this._list![index];
|
||||
},
|
||||
get(index) {
|
||||
return this.peekAt!(index);
|
||||
},
|
||||
get peek() {
|
||||
if (this._head === this._tail) return undefined;
|
||||
|
||||
return this._list![this._head!];
|
||||
},
|
||||
get peekFront() {
|
||||
return this.peek!;
|
||||
},
|
||||
get peekBack() {
|
||||
return this.peekAt!(-1);
|
||||
},
|
||||
unshift(item) {
|
||||
if (item === undefined) return this.size!;
|
||||
|
||||
this._head = (this._head! - 1 + this._list?.length!) & this._capacityMask!;
|
||||
this._list![this._head] = item;
|
||||
|
||||
if (this._tail === this._head) this._growArray!();
|
||||
|
||||
if (this._capacity && this.size! > this._capacity) this.pop!();
|
||||
|
||||
if (this._head < this._tail!) return this._tail! - this._head;
|
||||
else return this._capacityMask! + 1 - (this._head - this._tail!);
|
||||
},
|
||||
shift() {
|
||||
const head = this._head!;
|
||||
if (head === this._tail) return undefined;
|
||||
|
||||
this._list![head] = undefined;
|
||||
this._head = (head + 1) & this._capacityMask!;
|
||||
const item = this._list![head];
|
||||
if (
|
||||
head < 2 &&
|
||||
this._tail! > 10000 &&
|
||||
this._tail! <= this._list!.length >>> 2
|
||||
) {
|
||||
this._shrinkArray!();
|
||||
}
|
||||
|
||||
return item;
|
||||
},
|
||||
// push(item) {
|
||||
// if (item === undefined) return this.size!;
|
||||
// let tail = this._tail!;
|
||||
// this._list![tail] = item;
|
||||
// this._tail = (tail + 1) & this._capacityMask!;
|
||||
// if (this._tail === this._head) {
|
||||
// this._growArray!();
|
||||
// }
|
||||
// if (this._capacity && this.size! > this._capacity) {
|
||||
// this.shift!();
|
||||
// }
|
||||
// if (this._head! < this._tail) return this._tail - this._head!;
|
||||
// else return this._capacityMask! + 1 - (this._head! - this._tail);
|
||||
// },
|
||||
push(item) {
|
||||
if (item === undefined) return this.size!;
|
||||
|
||||
this._list![this._tail!] = item;
|
||||
this._tail! += 1 & this._capacityMask!;
|
||||
if (this._tail === this._head) {
|
||||
this._growArray!();
|
||||
}
|
||||
if (this._capacity && this.size! > this._capacity) {
|
||||
this.shift!();
|
||||
}
|
||||
if (this._head! < this._tail!) return this._tail! - this._head!;
|
||||
else return this._capacityMask! + 1 - (this._head! - this._tail!);
|
||||
},
|
||||
pop() {
|
||||
if (this._tail === this._head!) return undefined;
|
||||
|
||||
this._tail! = this._tail! - 1 + this._list!.length & this._capacityMask!;
|
||||
|
||||
const item = this._list![this._tail!];
|
||||
this._list![this._tail!] = undefined;
|
||||
|
||||
if (
|
||||
this._head! < 2 && this._tail! > 10000 &&
|
||||
this._tail! <= this._list!.length >>> 2
|
||||
) {
|
||||
this._shrinkArray!();
|
||||
}
|
||||
|
||||
return item;
|
||||
},
|
||||
removeOne(index) {
|
||||
// expect a number or return undefined
|
||||
if (index !== (index | 0)) return;
|
||||
|
||||
if (this._head === this._tail) return;
|
||||
|
||||
const size = this.size!;
|
||||
var len = this._list!.length;
|
||||
if (index >= size || index < -size) return;
|
||||
if (index < 0) index += size;
|
||||
index = (this._head! + index) & this._capacityMask!;
|
||||
var item = this._list![index];
|
||||
var k;
|
||||
if (index < size / 2) {
|
||||
for (k = index; k > 0; k--) {
|
||||
this._list![index] =
|
||||
this._list![(index = (index - 1 + len) & this._capacityMask!)];
|
||||
}
|
||||
this._list![index] = void 0;
|
||||
this._head = (this._head! + 1 + len) & this._capacityMask!;
|
||||
} else {
|
||||
for (k = size - 1 - index; k > 0; k--) {
|
||||
this._list![index] =
|
||||
this._list![(index = (index + 1 + len) & this._capacityMask!)];
|
||||
}
|
||||
this._list![index] = void 0;
|
||||
this._tail = (this._tail! - 1 + len) & this._capacityMask!;
|
||||
}
|
||||
|
||||
return item;
|
||||
},
|
||||
remove(index, count) {
|
||||
var i = index;
|
||||
var removed;
|
||||
var delCount = count;
|
||||
// expect a number or return undefined
|
||||
if (i !== (i | 0)) {
|
||||
return void 0;
|
||||
}
|
||||
if (this._head === this._tail) return void 0;
|
||||
var size = this.size!;
|
||||
var len = this._list!.length;
|
||||
if (i >= size || i < -size || count < 1) return void 0;
|
||||
if (i < 0) i += size;
|
||||
if (count === 1 || !count) {
|
||||
removed = new Array(1);
|
||||
removed[0] = this.removeOne!(i);
|
||||
return removed;
|
||||
}
|
||||
if (i === 0 && i + count >= size) {
|
||||
removed = this.toArray!();
|
||||
this.clear!();
|
||||
return removed;
|
||||
}
|
||||
if (i + count > size) count = size - i;
|
||||
var k;
|
||||
removed = new Array(count);
|
||||
for (k = 0; k < count; k++) {
|
||||
removed[k] = this._list![(this._head! + i + k) & this._capacityMask!];
|
||||
}
|
||||
i = (this._head! + i) & this._capacityMask!;
|
||||
if (index + count === size) {
|
||||
this._tail = (this._tail! - count + len) & this._capacityMask!;
|
||||
for (k = count; k > 0; k--) {
|
||||
this._list![(i = (i + 1 + len) & this._capacityMask!)] = void 0;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
if (index === 0) {
|
||||
this._head = (this._head! + count + len) & this._capacityMask!;
|
||||
for (k = count - 1; k > 0; k--) {
|
||||
this._list![(i = (i + 1 + len) & this._capacityMask!)] = void 0;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
if (i < size / 2) {
|
||||
this._head = (this._head! + index + count + len) & this._capacityMask!;
|
||||
for (k = index; k > 0; k--) {
|
||||
this.unshift!(this._list![(i = (i - 1 + len) & this._capacityMask!)]);
|
||||
}
|
||||
i = (this._head - 1 + len) & this._capacityMask!;
|
||||
while (delCount > 0) {
|
||||
this._list![(i = (i - 1 + len) & this._capacityMask!)] = void 0;
|
||||
delCount--;
|
||||
}
|
||||
if (index < 0) this._tail = i;
|
||||
} else {
|
||||
this._tail = i;
|
||||
i = (i + count + len) & this._capacityMask!;
|
||||
for (k = size - (count + index); k > 0; k--) {
|
||||
this.push!(this._list![i++]);
|
||||
}
|
||||
i = this._tail;
|
||||
while (delCount > 0) {
|
||||
this._list![(i = (i + 1 + len) & this._capacityMask!)] = void 0;
|
||||
delCount--;
|
||||
}
|
||||
}
|
||||
if (this._head! < 2 && this._tail! > 10000 && this._tail! <= len >>> 2) {
|
||||
this._shrinkArray!();
|
||||
}
|
||||
return removed;
|
||||
},
|
||||
splice(index, count) {
|
||||
var i = index;
|
||||
// expect a number or return undefined
|
||||
if (i !== (i | 0)) {
|
||||
return void 0;
|
||||
}
|
||||
var size = this.size!;
|
||||
if (i < 0) i += size;
|
||||
if (i > size) return void 0;
|
||||
if (arguments.length > 2) {
|
||||
var k, temp, removed;
|
||||
var argLen = arguments.length;
|
||||
var len = this._list!.length;
|
||||
var arguments_index = 2;
|
||||
if (!size || i < size / 2) {
|
||||
temp = new Array(i);
|
||||
for (k = 0; k < i; k++) {
|
||||
temp[k] = this._list![(this._head! + k) & this._capacityMask!];
|
||||
}
|
||||
if (count === 0) {
|
||||
removed = [];
|
||||
if (i > 0) {
|
||||
this._head = (this._head! + i + len) & this._capacityMask!;
|
||||
}
|
||||
} else {
|
||||
removed = this.remove!(i, count);
|
||||
this._head = (this._head! + i + len) & this._capacityMask!;
|
||||
}
|
||||
while (argLen > arguments_index) {
|
||||
this.unshift!(arguments[--argLen]);
|
||||
}
|
||||
for (k = i; k > 0; k--) {
|
||||
this.unshift!(temp[k - 1]);
|
||||
}
|
||||
} else {
|
||||
temp = new Array(size - (i + count));
|
||||
var leng = temp.length;
|
||||
for (k = 0; k < leng; k++) {
|
||||
temp[k] = this._list![
|
||||
(this._head! + i + count + k) & this._capacityMask!
|
||||
];
|
||||
}
|
||||
if (count === 0) {
|
||||
removed = [];
|
||||
if (i != size) {
|
||||
this._tail = (this._head! + i + len) & this._capacityMask!;
|
||||
}
|
||||
} else {
|
||||
removed = this.remove!(i, count);
|
||||
this._tail = (this._tail! - leng + len) & this._capacityMask!;
|
||||
}
|
||||
while (arguments_index < argLen) {
|
||||
this.push!(arguments[arguments_index++]);
|
||||
}
|
||||
for (k = 0; k < leng; k++) {
|
||||
this.push!(temp[k]);
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
} else {
|
||||
return this.remove!(i, count);
|
||||
}
|
||||
},
|
||||
clear() {
|
||||
this._head = 0;
|
||||
this._tail = 0;
|
||||
},
|
||||
get isEmpty() {
|
||||
return this._head === this._tail;
|
||||
},
|
||||
toArray() {
|
||||
return this._copyArray!(true);
|
||||
},
|
||||
get size() {
|
||||
if (this._head === this._tail) return 0;
|
||||
if (this._head! < this._tail!) return this._tail! - this._head!;
|
||||
else return this._capacityMask! + 1 - (this._head! - this._tail!);
|
||||
},
|
||||
_fromArray(array) {
|
||||
for (var i = 0; i < array.length; i++) this.push!(array[i]);
|
||||
},
|
||||
_copyArray(fullCopy: boolean) {
|
||||
let newArray = [];
|
||||
let list = this._list!;
|
||||
let len = list.length;
|
||||
let i;
|
||||
if (fullCopy || this._head! > this._tail!) {
|
||||
for (i = this._head!; i < len; i++) newArray.push(list[i]);
|
||||
for (i = 0; i < this._tail!; i++) newArray.push(list[i]);
|
||||
} else {
|
||||
for (i = this._head!; i < this._tail!; i++) newArray.push(list[i]);
|
||||
}
|
||||
return newArray;
|
||||
},
|
||||
_growArray() {
|
||||
if (this._head) {
|
||||
// copy existing data, head to end, then beginning to tail.
|
||||
this._list = this._copyArray!(true);
|
||||
this._head = 0;
|
||||
}
|
||||
|
||||
// head is at 0 and array is now full, safe to extend
|
||||
this._tail = this._list!.length;
|
||||
|
||||
this._list!.length *= 2;
|
||||
this._capacityMask = (this._capacityMask! << 1) | 1;
|
||||
},
|
||||
_shrinkArray() {
|
||||
console.log("list", this._list?.length);
|
||||
this._list!.length >>>= 1;
|
||||
console.log("len", this._capacityMask!);
|
||||
this._capacityMask! >>>= 1;
|
||||
},
|
||||
|
||||
get length() {
|
||||
return this.size!;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom implementation of a double ended queue.
|
||||
*/
|
||||
function Denque<T>(array?: T[], options?: IDenqueOptions): Denque<T> {
|
||||
const denque = Object.create(baseDenque, {
|
||||
_head: createNewProp(0),
|
||||
_tail: createNewProp(0),
|
||||
_capacity: createNewProp(options?.capacity),
|
||||
_capacityMask: createNewProp(0x3),
|
||||
_list: createNewProp(new Array(4)),
|
||||
}) as Denque<T>;
|
||||
|
||||
if (Array.isArray(array)) {
|
||||
denque._fromArray(array);
|
||||
}
|
||||
|
||||
return denque;
|
||||
}
|
||||
|
||||
const f = Denque<string>(["a", "b", "c", "d", "e"]);
|
||||
console.log(f.toArray());
|
||||
console.log(f.removeOne(1));
|
||||
console.log(f);
|
||||
console.log(f.toArray());
|
||||
|
||||
// import Denque from "https://esm.sh/denque@1.5.0";
|
||||
// const f = new Denque(["a", "a", "a", "a", "s"]);
|
||||
// console.log(f);
|
||||
Reference in New Issue
Block a user