db-discord
Version:
db-discord is a library that uses discord guilds and text channels as databases. db-discord relies on discord.js
244 lines (212 loc) • 7.86 kB
text/typescript
import * as https from "https"
import * as Discord from "db-discord-discord.js"
import XRegExp from "xregexp";
export function login(token: string): Promise<Discord.Client> {
return new Promise<Discord.Client>((resolve, reject) => {
let client = new Discord.Client()
client.on("ready", () => {
resolve(client)
})
client.on("error", reject)
client.login(token)
})
}
export function httpRequest(url: string) {
return new Promise<string>((resolve, reject) => {
https.get(url, resp => {
let data = "";
resp.on("data", chunk => {
data += chunk;
})
resp.on("end", () => {
resolve(data);
})
})
})
}
export function httpRequestAsBuffer(url: string) {
return new Promise<Buffer>((resolve, reject) => {
https.get(url, resp => {
let data: any[] = []
resp.on("data", chunk => {
data.push(chunk)
})
resp.on("end", () => {
resolve(Buffer.concat(data));
})
})
})
}
export type Regexify<T> = {
[P in keyof T]: RegExp
};
export async function recursiveSearch<T>(
channel: Discord.TextChannel,
searchTerm: string,
testerFunction: (obj: T) => boolean = () => true,
shouldAddFunction: (obj: T) => boolean = () => true,
converter: (message: Discord.Message) => Promise<T>): Promise<KeyPairValue<Discord.Message, T>[]> {
function searchResultMessages(result: Discord.MessageSearchResult) {
return flatMap(result.messages)
}
let buffer: KeyPairValue<Discord.Message, T>[] = []
let firstResult = await channel.search({
content: searchTerm,
});
let messages = await Promise.all(searchResultMessages(firstResult).map<Promise<KeyPairValue<Discord.Message, T>>>(async x => ({ Key: x, Value: await converter(x) })))
for (let i = 0; i < messages.length; i++) {
if (shouldAddFunction(messages[i].Value)) {
buffer.push(messages[i])
if (!testerFunction(messages[i].Value)) {
return buffer;
}
}
}
let maxValue = firstResult.totalResults
function clean() {
buffer = buffer.sort((a, b) => b.Key.createdTimestamp - a.Key.createdTimestamp)
let returnBuffer: KeyPairValue<Discord.Message, T>[] = []
let returnBufferId: string[] = []
buffer.forEach(x => {
if (!returnBufferId.includes(x.Key.id)) {
returnBuffer[returnBuffer.length] = x
returnBufferId[returnBufferId.length] = x.Key.id
}
})
buffer = returnBuffer
}
async function get(): Promise<{}> {
clean();
if (buffer.length >= maxValue) {
return {}
}
let result = await channel.search({
content: searchTerm,
maxID: buffer[buffer.length - 1].Key.id
})
let messages = await Promise.all(searchResultMessages(firstResult).map<Promise<KeyPairValue<Discord.Message, T>>>(async x => ({ Key: x, Value: await converter(x) })))
for (let i = 0; i < messages.length; i++) {
if (shouldAddFunction(messages[i].Value)) {
buffer.push(messages[i])
if (!testerFunction(messages[i].Value)) {
return {}
}
}
}
return await get();
}
await get();
return buffer;
}
export async function betterSearch<T>(
channel: Discord.TextChannel,
converter: (message: Discord.Message) => Promise<T>,
_searchTerm: Partial<T> | string,
regex: Partial<Regexify<T>> = {},
callback: (message: T) => boolean = (() => true)): Promise<KeyPairValue<string, T>[]> {
let searchTerm = "";
if (typeof _searchTerm === "object") {
searchTerm = (Object.getOwnPropertyNames(_searchTerm).map(x => (_searchTerm as any)[x]).join(","));
}
else {
searchTerm = _searchTerm;
}
let result = await recursiveSearch<T>(channel, searchTerm, callback, message => {
if (typeof _searchTerm === "object") {
return Object.getOwnPropertyNames(_searchTerm).every(y => {
let reg: RegExp | undefined = (regex as any)[y]
let value: any = (message as any)[y]
let searchValue: any = (_searchTerm as any)[y]
if (reg !== undefined) {
return reg.test(value)
}
return value === searchValue;
});
};
return true;
}, converter)
/*
if (typeof _searchTerm === "object") {
result = result.filter((x) => {
return Object.getOwnPropertyNames(_searchTerm).every(y => {
let reg: RegExp | undefined = (regex as any)[y]
let value: any = (x.Value as any)[y]
let searchValue: any = (_searchTerm as any)[y]
if (reg !== undefined) {
return reg.test(value)
}
return value === searchValue;
});
});
}
*/
return result.map(x => ({ Key: x.Key.id, Value: x.Value }))
}
export interface KeyPairValue<K, P> {
Key: K;
Value: P;
}
export function flatMap<T>(arr: T[][]): T[] {
return ([] as T[]).concat.apply([], arr) as T[]
}
export function GUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
let unicodeLettersAndNumbers = XRegExp("^(\\p{L}|\\p{N})")
export function isAlphanumerical(str: string): boolean[] {
return str.split("").map(x => unicodeLettersAndNumbers.test(x));
}
export function replaceCharacters(str: string, replacers: boolean[], replacement: string): string {
return str.split("").map((x, i) => replacers[i] ? x : replacement).join("")
}
export function removeUnacceptedCharactersForDiscord(str: string): string {
return replaceCharacters(str, isAlphanumerical(str), " ")
}
export function sleep(ms: number): Promise<{}> {
return new Promise<{}>((resolve, reject) => {
setTimeout(resolve)
})
}
/*
type PrimitiveType = "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "Object" | "function" | "null" | string
type PrimitiveTypeString = "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "Object" | "function" | "null"
interface PrimitiveType2 {
isArray: boolean;
possiblyTypes: PrimitiveTypeString[]
}
interface TypeAnalyzed {
[key: string]: PrimitiveType | TypeAnalyzed
}
export function getType(obj: any): PrimitiveType | TypeAnalyzed {
if (obj === null) {
return "null"
}
if (Array.isArray(obj)) {
let arrayTypes = obj.map(x => getType(x))
arrayTypes = arrayTypes.filter((a, b) => arrayTypes.indexOf(a) === b)
return "(" + arrayTypes.join("|") + ")[]"
}
return typeof obj
}
export function objectTypeAnalyze(obj: any): TypeAnalyzed {
function analyze(o: any): TypeAnalyzed {
let re: TypeAnalyzed = {}
Object.getOwnPropertyNames(o).forEach(name => {
let value = o[name]
let type = getType(value)
if (type === "object") {
re[name] = analyze(value)
}
else {
re[name] = type
}
})
return re;
}
let analyzed = analyze(obj)
return analyzed
}
*/