diff options
author | Madeline <46743919+MaddyUnderStars@users.noreply.github.com> | 2023-03-31 15:26:15 +1100 |
---|---|---|
committer | Madeline <46743919+MaddyUnderStars@users.noreply.github.com> | 2023-03-31 15:26:15 +1100 |
commit | 698ad90d3e82a15b85ceb021ad5667109ac0bcdb (patch) | |
tree | 7b79fc6d65e79af82b11d89cb1a5502a9f7bff08 /src/util | |
parent | fix: disable cache if multi threaded (diff) | |
download | server-698ad90d3e82a15b85ceb021ad5667109ac0bcdb.tar.xz |
Revert "Merge pull request #1008 from spacebarchat/dev/samuel"
This reverts commit 69ea71aa9e0bd2e5a98904a66fba0ad3745707cb, reversing changes made to 8b2faf0b18336e5dff1eeff4e849bcfd96b09e88.
Diffstat (limited to 'src/util')
42 files changed, 106 insertions, 482 deletions
diff --git a/src/util/cache/Cache.ts b/src/util/cache/Cache.ts deleted file mode 100644 index fb66c2e3..00000000 --- a/src/util/cache/Cache.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* - Fosscord: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Fosscord and Fosscord Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import { EntityMetadata, FindOptionsWhere } from "typeorm"; -import { LocalCache } from "./LocalCache"; - -declare module "typeorm" { - interface BaseEntity { - metadata?: EntityMetadata; - cache: CacheManager; - } -} - -export type BaseEntityWithId = { id: string; [name: string]: any }; -export type Criteria = - | string - | string[] - | number - | number[] - | FindOptionsWhere<never>; - -export interface Cache { - get(id: string): BaseEntityWithId | undefined; - set(id: string, entity: BaseEntityWithId): this; - find(options: Record<string, never>): BaseEntityWithId | undefined; - filter(options: Record<string, never>): BaseEntityWithId[]; - delete(id: string): boolean; -} - -export class CacheManager { - // last access time to automatically remove old entities from cache after 5 minutes of inactivity (to prevent memory leaks) - cache: Cache; - - constructor() { - this.cache = new LocalCache(); - // TODO: Config.get().cache.redis; - } - - delete(id: string) { - return this.cache.delete(id); - } - - insert(entity: BaseEntityWithId) { - if (!entity.id) return; - - return this.cache.set(entity.id, entity); - } - - find(options?: Record<string, never>, select?: string[] | undefined) { - if (!options) return null; - const entity = this.cache.find(options); - if (!entity) return null; - if (!select) return entity; - - const result = {}; - for (const prop of select) { - // @ts-ignore - result[prop] = entity[prop]; - } - - // @ts-ignore - return entity.constructor.create(result); - } - - filter(options: Record<string, never>) { - return this.cache.filter(options); - } -} diff --git a/src/util/cache/EntityCache.ts b/src/util/cache/EntityCache.ts deleted file mode 100644 index ba1e5bd8..00000000 --- a/src/util/cache/EntityCache.ts +++ /dev/null @@ -1,162 +0,0 @@ -/* - Fosscord: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Fosscord and Fosscord Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ -/* eslint-disable */ -import { - DataSource, - FindOneOptions, - EntityNotFoundError, - FindOptionsWhere, -} from "typeorm"; -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity"; -import { BaseClassWithId } from "../entities/BaseClass"; -import { Config, getDatabase, RabbitMQ } from "../util"; -import { CacheManager } from "./Cache"; - -function getObjectKeysAsArray(obj?: Record<string, any>) { - if (!obj) return []; - if (Array.isArray(obj)) return obj; - return Object.keys(obj); -} - -export type ThisType<T> = { - new (): T; -} & typeof BaseEntityCache; - -interface BaseEntityCache { - constructor: typeof BaseEntityCache; -} - -// @ts-ignore -class BaseEntityCache extends BaseClassWithId { - static cache: CacheManager; - static cacheEnabled: boolean; - - public get metadata() { - return getDatabase()?.getMetadata(this.constructor)!; - } - - static useDataSource(dataSource: DataSource | null) { - super.useDataSource(dataSource); - const isMultiThreaded = - process.env.EVENT_TRANSMISSION === "process" || RabbitMQ.connection; - this.cacheEnabled = Config.get().cache.enabled ?? !isMultiThreaded; - if (Config.get().cache.redis) return; // TODO: Redis cache - if (!this.cacheEnabled) return; - this.cache = new CacheManager(); - } - - static async findOne<T extends BaseEntityCache>( - this: ThisType<T>, - options: FindOneOptions<T>, - ) { - // @ts-ignore - if (!this.cacheEnabled) return super.findOne(options); - let select = getObjectKeysAsArray(options.select); - - if (!select.length) { - // get all columns that are marked as select - getDatabase() - ?.getMetadata(this) - .columns.forEach((x) => { - if (!x.isSelect) return; - select.push(x.propertyName); - }); - } - if (options.relations) { - select.push(...getObjectKeysAsArray(options.relations)); - } - - const cacheResult = this.cache.find(options.where as never, select); - if (cacheResult) { - const hasAllProps = select.every((key) => { - if (key.includes(".")) return true; // @ts-ignore - return cacheResult[key] !== undefined; - }); - // console.log(`[Cache] get ${cacheResult.id} from ${cacheResult.constructor.name}`,); - if (hasAllProps) return cacheResult; - } - - // @ts-ignore - const result = await super.findOne<T>(options); - if (!result) return null; - - this.cache.insert(result as any); - - return result; - } - - static async findOneOrFail<T extends BaseEntityCache>( - this: ThisType<T>, - options: FindOneOptions<T>, - ) { - const result = await this.findOne<T>(options); - if (!result) throw new EntityNotFoundError(this, options); - return result; - } - - save() { - if (this.constructor.cacheEnabled) this.constructor.cache.insert(this); - return super.save(); - } - - remove() { - if (this.constructor.cacheEnabled) - this.constructor.cache.delete(this.id); - return super.remove(); - } - - static async update<T extends BaseEntityCache>( - this: ThisType<T>, - criteria: FindOptionsWhere<T>, - partialEntity: QueryDeepPartialEntity<T>, - ) { - // @ts-ignore - const result = super.update<T>(criteria, partialEntity); - if (!this.cacheEnabled) return result; - - const entities = this.cache.filter(criteria as never); - for (const entity of entities) { - // @ts-ignore - partialEntity.id = entity.id; - this.cache.insert(partialEntity as never); - } - - return result; - } - - static async delete<T extends BaseEntityCache>( - this: ThisType<T>, - criteria: FindOptionsWhere<T>, - ) { - // @ts-ignore - const result = super.delete<T>(criteria); - if (!this.cacheEnabled) return result; - - const entities = this.cache.filter(criteria as never); - for (const entity of entities) { - this.cache.delete(entity.id); - } - - return result; - } -} - -// needed, because typescript can't infer the type of the static methods with generics -const EntityCache = BaseEntityCache as unknown as typeof BaseClassWithId; - -export { EntityCache }; diff --git a/src/util/cache/LocalCache.ts b/src/util/cache/LocalCache.ts deleted file mode 100644 index 9c4f23b3..00000000 --- a/src/util/cache/LocalCache.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - Fosscord: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Fosscord and Fosscord Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { BaseEntityWithId, Cache } from "./Cache"; - -export const cacheTimeout = 1000 * 60 * 5; - -export class LocalCache extends Map<string, BaseEntityWithId> implements Cache { - last_access = new Map<string, number>(); - - constructor() { - super(); - - setInterval(() => { - const now = Date.now(); - for (const [key, value] of this.last_access) { - if (now - value > cacheTimeout) { - this.delete(key); - this.last_access.delete(key); - } - } - }, cacheTimeout); - } - - set(key: string, value: BaseEntityWithId): this { - if (this.has(key)) { - this.update(key, value); - return this; - } - this.last_access.set(key, Date.now()); - return super.set(key, value as never); - } - - get(key: string) { - const value = super.get(key); - if (value) this.last_access.set(key, Date.now()); - return value; - } - - update(id: string, entity: BaseEntityWithId) { - const oldEntity = this.get(id); - if (!oldEntity) return; - for (const key in entity) { - // @ts-ignore - if (entity[key] === undefined) continue; // @ts-ignore - oldEntity[key] = entity[key]; - } - } - - find(options: Record<string, never>): BaseEntityWithId | undefined { - if (options.id && Object.keys(options).length === 1) { - return this.get(options.id); - } - for (const entity of this.values()) { - if (objectFulfillsQuery(entity, options)) return entity; - } - } - - filter(options: Record<string, never>): BaseEntityWithId[] { - const result = []; - for (const entity of this.values()) { - if (objectFulfillsQuery(entity, options)) { - result.push(entity); - } - } - return result; - } -} - -function objectFulfillsQuery( - entity: BaseEntityWithId, - options: Record<string, never>, -) { - for (const key in options) { - // @ts-ignore - if (entity[key] !== options[key]) return false; - } - return true; -} diff --git a/src/util/cache/index.ts b/src/util/cache/index.ts deleted file mode 100644 index 43f0aa96..00000000 --- a/src/util/cache/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./EntityCache"; -export * from "./Cache"; -export * from "./LocalCache"; diff --git a/src/util/config/Config.ts b/src/util/config/Config.ts index 7de01b66..90b98b7a 100644 --- a/src/util/config/Config.ts +++ b/src/util/config/Config.ts @@ -37,7 +37,6 @@ import { SecurityConfiguration, SentryConfiguration, TemplateConfiguration, - CacheConfiguration, } from "../config"; export class ConfigValue { @@ -62,5 +61,4 @@ export class ConfigValue { email: EmailConfiguration = new EmailConfiguration(); passwordReset: PasswordResetConfiguration = new PasswordResetConfiguration(); - cache: CacheConfiguration = new CacheConfiguration(); } diff --git a/src/util/config/types/CacheConfiguration.ts b/src/util/config/types/CacheConfiguration.ts deleted file mode 100644 index 4178090e..00000000 --- a/src/util/config/types/CacheConfiguration.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - Fosscord: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Fosscord and Fosscord Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -export class CacheConfiguration { - enabled: boolean | null = true; - redis: string | null = null; -} diff --git a/src/util/config/types/index.ts b/src/util/config/types/index.ts index a52ca627..782ebfc3 100644 --- a/src/util/config/types/index.ts +++ b/src/util/config/types/index.ts @@ -17,7 +17,6 @@ */ export * from "./ApiConfiguration"; -export * from "./CacheConfiguration"; export * from "./CdnConfiguration"; export * from "./DefaultsConfiguration"; export * from "./EmailConfiguration"; diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts index e0cdc481..962b2a8e 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Team } from "./Team"; import { User } from "./User"; @Entity("applications") -export class Application extends EntityCache { +export class Application extends BaseClass { @Column() name: string; diff --git a/src/util/entities/Attachment.ts b/src/util/entities/Attachment.ts index 521be583..d60ac41c 100644 --- a/src/util/entities/Attachment.ts +++ b/src/util/entities/Attachment.ts @@ -25,11 +25,11 @@ import { RelationId, } from "typeorm"; import { URL } from "url"; -import { EntityCache } from "../cache"; import { deleteFile } from "../util/cdn"; +import { BaseClass } from "./BaseClass"; @Entity("attachments") -export class Attachment extends EntityCache { +export class Attachment extends BaseClass { @Column() filename: string; // name of file attached diff --git a/src/util/entities/AuditLog.ts b/src/util/entities/AuditLog.ts index 9768ef04..e47f92fb 100644 --- a/src/util/entities/AuditLog.ts +++ b/src/util/entities/AuditLog.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { ChannelPermissionOverwrite } from "./Channel"; import { User } from "./User"; @@ -112,7 +112,7 @@ export enum AuditLogEvents { } @Entity("audit_logs") -export class AuditLog extends EntityCache { +export class AuditLog extends BaseClass { @JoinColumn({ name: "target_id" }) @ManyToOne(() => User) target?: User; diff --git a/src/util/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts index 3d40338e..61e8f12a 100644 --- a/src/util/entities/BackupCodes.ts +++ b/src/util/entities/BackupCodes.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { User } from "./User"; import crypto from "crypto"; @Entity("backup_codes") -export class BackupCode extends EntityCache { +export class BackupCode extends BaseClass { @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) user: User; diff --git a/src/util/entities/Ban.ts b/src/util/entities/Ban.ts index 2b3b688b..1693cd40 100644 --- a/src/util/entities/Ban.ts +++ b/src/util/entities/Ban.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; @Entity("bans") -export class Ban extends EntityCache { +export class Ban extends BaseClass { @Column({ nullable: true }) @RelationId((ban: Ban) => ban.user) user_id: string; diff --git a/src/util/entities/BaseClass.ts b/src/util/entities/BaseClass.ts index d2770bfd..f4b3cf59 100644 --- a/src/util/entities/BaseClass.ts +++ b/src/util/entities/BaseClass.ts @@ -25,12 +25,16 @@ import { PrimaryColumn, } from "typeorm"; import { Snowflake } from "../util/Snowflake"; +import { getDatabase } from "../util/Database"; import { OrmUtils } from "../imports/OrmUtils"; -import { getDatabase } from "../util"; export class BaseClassWithoutId extends BaseEntity { - public get metadata() { - return getDatabase()?.getMetadata(this.constructor); + private get construct() { + return this.constructor; + } + + private get metadata() { + return getDatabase()?.getMetadata(this.construct); } assign(props: object) { @@ -57,23 +61,8 @@ export class BaseClassWithoutId extends BaseEntity { ), ); } -} - -export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") - ? ObjectIdColumn - : PrimaryColumn; - -export class BaseClassWithId extends BaseClassWithoutId { - @PrimaryIdColumn() - id: string = Snowflake.generate(); - - @BeforeUpdate() - @BeforeInsert() - _do_validate() { - if (!this.id) this.id = Snowflake.generate(); - } - static increment<T extends BaseClassWithId>( + static increment<T extends BaseClass>( conditions: FindOptionsWhere<T>, propertyPath: string, value: number | string, @@ -82,7 +71,7 @@ export class BaseClassWithId extends BaseClassWithoutId { return repository.increment(conditions, propertyPath, value); } - static decrement<T extends BaseClassWithId>( + static decrement<T extends BaseClass>( conditions: FindOptionsWhere<T>, propertyPath: string, value: number | string, @@ -91,3 +80,18 @@ export class BaseClassWithId extends BaseClassWithoutId { return repository.decrement(conditions, propertyPath, value); } } + +export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") + ? ObjectIdColumn + : PrimaryColumn; + +export class BaseClass extends BaseClassWithoutId { + @PrimaryIdColumn() + id: string = Snowflake.generate(); + + @BeforeUpdate() + @BeforeInsert() + _do_validate() { + if (!this.id) this.id = Snowflake.generate(); + } +} diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 218907ed..9ce04848 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -24,7 +24,7 @@ import { OneToMany, RelationId, } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { PublicUserProjection, User } from "./User"; import { HTTPError } from "lambert-server"; @@ -70,7 +70,7 @@ export enum ChannelType { } @Entity("channels") -export class Channel extends EntityCache { +export class Channel extends BaseClass { @Column() created_at: Date; diff --git a/src/util/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts index a26bcd8a..cfbc3a9b 100644 --- a/src/util/entities/ClientRelease.ts +++ b/src/util/entities/ClientRelease.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; @Entity("client_release") -export class Release extends EntityCache { +export class Release extends BaseClass { @Column() name: string; diff --git a/src/util/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts index 8ef03fea..33550197 100644 --- a/src/util/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { User } from "./User"; export type PublicConnectedAccount = Pick< @@ -26,7 +26,7 @@ export type PublicConnectedAccount = Pick< >; @Entity("connected_accounts") -export class ConnectedAccount extends EntityCache { +export class ConnectedAccount extends BaseClass { @Column({ nullable: true }) @RelationId((account: ConnectedAccount) => account.user) user_id: string; diff --git a/src/util/entities/EmbedCache.ts b/src/util/entities/EmbedCache.ts index 49361032..8ff2a457 100644 --- a/src/util/entities/EmbedCache.ts +++ b/src/util/entities/EmbedCache.ts @@ -16,12 +16,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Entity, Column } from "typeorm"; import { Embed } from "./Message"; @Entity("embed_cache") -export class EmbedCache extends EntityCache { +export class EmbedCache extends BaseClass { @Column() url: string; diff --git a/src/util/entities/Emoji.ts b/src/util/entities/Emoji.ts index bf15f4ec..f1bf2d59 100644 --- a/src/util/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts @@ -18,11 +18,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { User } from "."; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; @Entity("emojis") -export class Emoji extends EntityCache { +export class Emoji extends BaseClass { @Column() animated: boolean; diff --git a/src/util/entities/Encryption.ts b/src/util/entities/Encryption.ts index 24fbaa6c..8325bdee 100644 --- a/src/util/entities/Encryption.ts +++ b/src/util/entities/Encryption.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; @Entity("security_settings") -export class SecuritySettings extends EntityCache { +export class SecuritySettings extends BaseClass { @Column({ nullable: true }) guild_id: string; diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index 7253f118..b1693838 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -26,7 +26,7 @@ import { } from "typeorm"; import { Config, handleFile, Snowflake } from ".."; import { Ban } from "./Ban"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Emoji } from "./Emoji"; import { Invite } from "./Invite"; @@ -67,7 +67,7 @@ export const PublicGuildRelations = [ ]; @Entity("guilds") -export class Guild extends EntityCache { +export class Guild extends BaseClass { @Column({ nullable: true }) @RelationId((guild: Guild) => guild.afk_channel) afk_channel_id?: string; diff --git a/src/util/entities/Message.ts b/src/util/entities/Message.ts index db98a6f2..519c431e 100644 --- a/src/util/entities/Message.ts +++ b/src/util/entities/Message.ts @@ -34,7 +34,7 @@ import { OneToMany, RelationId, } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { Webhook } from "./Webhook"; import { Sticker } from "./Sticker"; @@ -70,7 +70,7 @@ export enum MessageType { @Entity("messages") @Index(["channel_id", "id"], { unique: true }) -export class Message extends EntityCache { +export class Message extends BaseClass { @Column({ nullable: true }) @RelationId((message: Message) => message.channel) @Index() diff --git a/src/util/entities/Note.ts b/src/util/entities/Note.ts index 2005ab0f..196f6861 100644 --- a/src/util/entities/Note.ts +++ b/src/util/entities/Note.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, Unique } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { User } from "./User"; @Entity("notes") @Unique(["owner", "target"]) -export class Note extends EntityCache { +export class Note extends BaseClass { @JoinColumn({ name: "owner_id" }) @ManyToOne(() => User, { onDelete: "CASCADE" }) owner: User; diff --git a/src/util/entities/RateLimit.ts b/src/util/entities/RateLimit.ts index 5402ad06..8d00f59a 100644 --- a/src/util/entities/RateLimit.ts +++ b/src/util/entities/RateLimit.ts @@ -17,10 +17,10 @@ */ import { Column, Entity } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; @Entity("rate_limits") -export class RateLimit extends EntityCache { +export class RateLimit extends BaseClass { @Column() // no relation as it also executor_id: string; diff --git a/src/util/entities/ReadState.ts b/src/util/entities/ReadState.ts index 56856a1e..1b280d12 100644 --- a/src/util/entities/ReadState.ts +++ b/src/util/entities/ReadState.ts @@ -24,7 +24,7 @@ import { ManyToOne, RelationId, } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { User } from "./User"; @@ -34,7 +34,7 @@ import { User } from "./User"; @Entity("read_states") @Index(["channel_id", "user_id"], { unique: true }) -export class ReadState extends EntityCache { +export class ReadState extends BaseClass { @Column() @RelationId((read_state: ReadState) => read_state.channel) channel_id: string; diff --git a/src/util/entities/Recipient.ts b/src/util/entities/Recipient.ts index 32ae7936..797349e5 100644 --- a/src/util/entities/Recipient.ts +++ b/src/util/entities/Recipient.ts @@ -17,10 +17,10 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; @Entity("recipients") -export class Recipient extends EntityCache { +export class Recipient extends BaseClass { @Column() @RelationId((recipient: Recipient) => recipient.channel) channel_id: string; diff --git a/src/util/entities/Relationship.ts b/src/util/entities/Relationship.ts index e67557aa..740095c2 100644 --- a/src/util/entities/Relationship.ts +++ b/src/util/entities/Relationship.ts @@ -24,7 +24,7 @@ import { ManyToOne, RelationId, } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { User } from "./User"; export enum RelationshipType { @@ -36,7 +36,7 @@ export enum RelationshipType { @Entity("relationships") @Index(["from_id", "to_id"], { unique: true }) -export class Relationship extends EntityCache { +export class Relationship extends BaseClass { @Column({}) @RelationId((relationship: Relationship) => relationship.from) from_id: string; diff --git a/src/util/entities/Role.ts b/src/util/entities/Role.ts index 2fb63e93..85877c12 100644 --- a/src/util/entities/Role.ts +++ b/src/util/entities/Role.ts @@ -18,11 +18,11 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; @Entity("roles") -export class Role extends EntityCache { +export class Role extends BaseClass { @Column({ nullable: true }) @RelationId((role: Role) => role.guild) guild_id: string; diff --git a/src/util/entities/SecurityKey.ts b/src/util/entities/SecurityKey.ts index cdcc814b..fd7a4c5e 100644 --- a/src/util/entities/SecurityKey.ts +++ b/src/util/entities/SecurityKey.ts @@ -17,11 +17,11 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { User } from "./User"; @Entity("security_keys") -export class SecurityKey extends EntityCache { +export class SecurityKey extends BaseClass { @Column({ nullable: true }) @RelationId((key: SecurityKey) => key.user) user_id: string; diff --git a/src/util/entities/Session.ts b/src/util/entities/Session.ts index a03ff114..6c6f7caa 100644 --- a/src/util/entities/Session.ts +++ b/src/util/entities/Session.ts @@ -17,7 +17,7 @@ */ import { User } from "./User"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { Status } from "../interfaces/Status"; import { Activity } from "../interfaces/Activity"; @@ -25,7 +25,7 @@ import { Activity } from "../interfaces/Activity"; //TODO we need to remove all sessions on server start because if the server crashes without closing websockets it won't delete them @Entity("sessions") -export class Session extends EntityCache { +export class Session extends BaseClass { @Column({ nullable: true }) @RelationId((session: Session) => session.user) user_id: string; diff --git a/src/util/entities/Sticker.ts b/src/util/entities/Sticker.ts index 9139a5b1..cd07e65a 100644 --- a/src/util/entities/Sticker.ts +++ b/src/util/entities/Sticker.ts @@ -18,7 +18,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { User } from "./User"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; export enum StickerType { @@ -34,7 +34,7 @@ export enum StickerFormatType { } @Entity("stickers") -export class Sticker extends EntityCache { +export class Sticker extends BaseClass { @Column() name: string; diff --git a/src/util/entities/StickerPack.ts b/src/util/entities/StickerPack.ts index cc5c392b..61ab1287 100644 --- a/src/util/entities/StickerPack.ts +++ b/src/util/entities/StickerPack.ts @@ -25,10 +25,10 @@ import { RelationId, } from "typeorm"; import { Sticker } from "."; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; @Entity("sticker_packs") -export class StickerPack extends EntityCache { +export class StickerPack extends BaseClass { @Column() name: string; diff --git a/src/util/entities/Team.ts b/src/util/entities/Team.ts index 04d34d30..7bedc4af 100644 --- a/src/util/entities/Team.ts +++ b/src/util/entities/Team.ts @@ -24,12 +24,12 @@ import { OneToMany, RelationId, } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { TeamMember } from "./TeamMember"; import { User } from "./User"; @Entity("teams") -export class Team extends EntityCache { +export class Team extends BaseClass { @Column({ nullable: true }) icon?: string; diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts index d2053bb7..539da957 100644 --- a/src/util/entities/TeamMember.ts +++ b/src/util/entities/TeamMember.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { User } from "./User"; export enum TeamMemberState { @@ -26,7 +26,7 @@ export enum TeamMemberState { } @Entity("team_members") -export class TeamMember extends EntityCache { +export class TeamMember extends BaseClass { @Column({ type: "int" }) membership_state: TeamMemberState; diff --git a/src/util/entities/Template.ts b/src/util/entities/Template.ts index 101329d1..c417f1f0 100644 --- a/src/util/entities/Template.ts +++ b/src/util/entities/Template.ts @@ -17,12 +17,12 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; @Entity("templates") -export class Template extends EntityCache { +export class Template extends BaseClass { @Column({ unique: true }) code: string; diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index ec7a11d6..df9af328 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -34,7 +34,7 @@ import { trimSpecial, } from ".."; import { BitField } from "../util/BitField"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { ConnectedAccount } from "./ConnectedAccount"; import { Member } from "./Member"; import { Relationship } from "./Relationship"; @@ -94,7 +94,7 @@ export interface UserPrivate extends Pick<User, PrivateUserKeys> { } @Entity("users") -export class User extends EntityCache { +export class User extends BaseClass { @Column() username: string; // username max length 32, min 2 (should be configurable) diff --git a/src/util/entities/VoiceState.ts b/src/util/entities/VoiceState.ts index 826ae0e3..b291c4d3 100644 --- a/src/util/entities/VoiceState.ts +++ b/src/util/entities/VoiceState.ts @@ -17,7 +17,7 @@ */ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -25,7 +25,7 @@ import { Member } from "./Member"; //https://gist.github.com/vassjozsef/e482c65df6ee1facaace8b3c9ff66145#file-voice_state-ex @Entity("voice_states") -export class VoiceState extends EntityCache { +export class VoiceState extends BaseClass { @Column({ nullable: true }) @RelationId((voice_state: VoiceState) => voice_state.guild) guild_id: string; diff --git a/src/util/entities/Webhook.ts b/src/util/entities/Webhook.ts index eeabfea5..91498a22 100644 --- a/src/util/entities/Webhook.ts +++ b/src/util/entities/Webhook.ts @@ -18,7 +18,7 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { Application } from "./Application"; -import { EntityCache } from "../cache"; +import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -30,7 +30,7 @@ export enum WebhookType { } @Entity("webhooks") -export class Webhook extends EntityCache { +export class Webhook extends BaseClass { @Column({ type: "int" }) type: WebhookType; diff --git a/src/util/schemas/Validator.ts b/src/util/schemas/Validator.ts index 84677e25..1de511d3 100644 --- a/src/util/schemas/Validator.ts +++ b/src/util/schemas/Validator.ts @@ -43,7 +43,7 @@ export const ajv = new Ajv({ allowUnionTypes: true, }); -addFormats(ajv as never); +addFormats(ajv); export function validateSchema<G extends object>(schema: string, data: G): G { const valid = ajv.validate(schema, normalizeBody(data)); diff --git a/src/util/util/Database.ts b/src/util/util/Database.ts index b0d9d24e..e23bb895 100644 --- a/src/util/util/Database.ts +++ b/src/util/util/Database.ts @@ -38,8 +38,7 @@ const dbConnectionString = const DatabaseType = dbConnectionString.includes("://") ? dbConnectionString.split(":")[0]?.replace("+srv", "") - : "better-sqlite3"; - + : "sqlite"; const isSqlite = DatabaseType.includes("sqlite"); const DataSourceOptions = new DataSource({ @@ -51,7 +50,7 @@ const DataSourceOptions = new DataSource({ database: isSqlite ? dbConnectionString : undefined, entities: [path.join(__dirname, "..", "entities", "*.js")], synchronize: !!process.env.DB_SYNC, - logging: process.env["DB_LOGGING"] === "true", + logging: false, bigNumberStrings: false, supportBigNumbers: true, name: "default", @@ -78,13 +77,7 @@ export async function initDatabase(): Promise<DataSource> { } if (!process.env.DB_SYNC) { - const supported = [ - "mysql", - "mariadb", - "postgres", - "sqlite", - "better-sqlite3", - ]; + const supported = ["mysql", "mariadb", "postgres", "sqlite"]; if (!supported.includes(DatabaseType)) { console.log( "[Database]" + @@ -120,10 +113,10 @@ export async function initDatabase(): Promise<DataSource> { // Manually insert every current migration to prevent this: await Promise.all( dbConnection.migrations.map((migration) => - Migration.create({ + Migration.insert({ name: migration.name, timestamp: Date.now(), - }).save(), + }), ), ); } else { diff --git a/src/util/util/Permissions.ts b/src/util/util/Permissions.ts index 4aeb9268..996c72ea 100644 --- a/src/util/util/Permissions.ts +++ b/src/util/util/Permissions.ts @@ -257,26 +257,23 @@ export async function getPermission( } if (guild_id) { - const result = await Promise.all([ - Guild.findOneOrFail({ - where: { id: guild_id }, - select: ["id", "owner_id", ...(opts.guild_select || [])], - relations: opts.guild_relations, - }), - Member.findOneOrFail({ - where: { guild_id, id: user_id }, - relations: ["roles", ...(opts.member_relations || [])], - // select: [ - // "id", // TODO: Bug in typeorm? adding these selects breaks the query. - // "roles", - // ...(opts.member_select || []), - // ], - }), - ]); - guild = result[0]; - member = result[1]; + guild = await Guild.findOneOrFail({ + where: { id: guild_id }, + select: ["id", "owner_id", ...(opts.guild_select || [])], + relations: opts.guild_relations, + }); if (guild.owner_id === user_id) return new Permissions(Permissions.FLAGS.ADMINISTRATOR); + + member = await Member.findOneOrFail({ + where: { guild_id, id: user_id }, + relations: ["roles", ...(opts.member_relations || [])], + // select: [ + // "id", // TODO: Bug in typeorm? adding these selects breaks the query. + // "roles", + // ...(opts.member_select || []), + // ], + }); } let recipient_ids = channel?.recipients?.map((x) => x.user_id); diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts index b839a519..50e63c5f 100644 --- a/src/util/util/Token.ts +++ b/src/util/util/Token.ts @@ -19,7 +19,6 @@ import jwt, { VerifyOptions } from "jsonwebtoken"; import { Config } from "./Config"; import { User } from "../entities"; -import { KeyObject } from "crypto"; export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] }; @@ -63,7 +62,7 @@ async function checkEmailToken( export function checkToken( token: string, - jwtSecret: string | KeyObject, + jwtSecret: string, isEmailVerification = false, ): Promise<UserTokenData> { return new Promise((res, rej) => { @@ -87,7 +86,7 @@ export function checkToken( const user = await User.findOne({ where: { id: decoded.id }, - select: ["id", "data", "bot", "disabled", "deleted", "rights"], + select: ["data", "bot", "disabled", "deleted", "rights"], }); if (!user) return rej("Invalid Token"); diff --git a/src/util/util/index.ts b/src/util/util/index.ts index 10ae7152..838239b7 100644 --- a/src/util/util/index.ts +++ b/src/util/util/index.ts @@ -24,7 +24,7 @@ export * from "./cdn"; export * from "./Config"; export * from "./Constants"; export * from "./Database"; -export * from "./email/index"; +export * from "./email"; export * from "./Event"; export * from "./FieldError"; export * from "./Intents"; |