diff --git a/.docker/env b/.docker/env new file mode 100644 index 00000000..595b7ba2 --- /dev/null +++ b/.docker/env @@ -0,0 +1 @@ +MONGO_URL=mongodb://db:27017/fosscord?readPreference=secondaryPreferred diff --git a/api/.github/FUNDING.yml b/.github/FUNDING.yml similarity index 100% rename from api/.github/FUNDING.yml rename to .github/FUNDING.yml diff --git a/api/.github/workflows/release.yml b/.github/workflows/release.yml similarity index 64% rename from api/.github/workflows/release.yml rename to .github/workflows/release.yml index 3ef40aeb..b0a31780 100644 --- a/api/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,13 +15,13 @@ jobs: include: - os: windows build: npm run bundle:windows - artifact: fosscord-api-windows.exe + artifact: fosscord-server-windows.exe - os: macos build: npm run bundle:macos - artifact: fosscord-api-macos.app.tgz + artifact: fosscord-server-macos.app.tgz - os: ubuntu build: npm run bundle:linux - artifact: fosscord-api-linux.tgz + artifact: fosscord-server-linux.tgz runs-on: ${{ matrix.os }}-latest steps: - uses: actions/checkout@v2 @@ -29,6 +29,8 @@ jobs: with: node-version: 14 - run: npm install + env: + MONGOMS_VERSION: 4.4.3 - run: npm run build - run: ${{ matrix.build }} - uses: actions/upload-artifact@v2 @@ -46,43 +48,52 @@ jobs: uses: Saionaro/extract-package-version@v1.0.6 - uses: actions/download-artifact@v2 with: - name: fosscord-api-windows-${{ github.sha }}.exe + name: fosscord-server-windows.exe - uses: actions/download-artifact@v2 with: - name: fosscord-api-macos-${{ github.sha }}.app.tgz + name: fosscord-server-macos.app.tgz - uses: actions/download-artifact@v2 with: - name: fosscord-api-linux-${{ github.sha }}.tgz + name: fosscord-server-linux.tgz - uses: actions/create-release@v1 id: create-release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: v${{ steps.extract_version.outputs.version }} - release_name: Release ${{ steps.extract_version.outputs.version }} + release_name: Server v${{ steps.extract_version.outputs.version }} draft: false prerelease: true # TODO: change this to false + body: > + ## Download + + - [Windows](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-windows.exe) + + - [MacOS](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-macos.app.tgz) + + - [Linux](https://github.com/fosscord/fosscord-server/releases/download/v${{ steps.extract_version.outputs.version }}/fosscord-server-linux.tgz) + - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: fosscord-api-windows-${{ github.sha }}.exe - asset_name: fosscord-api-windows.exe + asset_path: fosscord-server-windows.exe + asset_name: fosscord-server-windows.exe asset_content_type: application/vnd.microsoft.portable-executable - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: fosscord-api-macos-${{ github.sha }}.app.tgz - asset_name: fosscord-api-macos.app.tgz + asset_path: fosscord-server-macos.app.tgz + asset_name: fosscord-server-macos.app.tgz asset_content_type: application/gzip - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: fosscord-api-linux-${{ github.sha }}.tgz - asset_name: fosscord-api-linux.tgz - asset_content_type: application/gzip + asset_path: fosscord-server-linux.tgz + asset_name: fosscord-server-linux.tgz + asset_content_type: application/gzip \ No newline at end of file diff --git a/.gitignore b/.gitignore index c2658d7d..c2636bf1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -node_modules/ +.DS_STORE +db/ +dist/ +node_modules diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 07fd32ac..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "sourceMaps": true, - "type": "node", - "request": "launch", - "name": "Launch Server", - "program": "${workspaceFolder}/dist/index.js", - "preLaunchTask": "tsc: build - tsconfig.json", - "outFiles": ["${workspaceFolder}/dist/**/*.js"] - } - ] -} diff --git a/api/.github/ISSUE_TEMPLATE/-feature--.md b/api/.github/ISSUE_TEMPLATE/-feature--.md deleted file mode 100644 index cefcf6b6..00000000 --- a/api/.github/ISSUE_TEMPLATE/-feature--.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: "[Feature] " -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/api/.github/workflows/codeql-analysis.yml b/api/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 3a3a8e92..00000000 --- a/api/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,71 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '25 10 * * 5' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/api/.github/workflows/docker-publish.yml b/api/.github/workflows/docker-publish.yml deleted file mode 100644 index 46d9d04d..00000000 --- a/api/.github/workflows/docker-publish.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: docker-publish - -on: - push: - branches: - - 'master' - -jobs: - docker: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - push: true - tags: ${{ secrets.DOCKERHUB_TAGS }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new - - - # Hackfix to cleanup cache; replace after buildx 0.6 and BuildKit 0.9 are released - # https://github.com/docker/build-push-action/pull/406#issuecomment-879184394 - name: Move cache fix - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/api/package-lock.json b/api/package-lock.json index e4cf20be..c030e642 100644 Binary files a/api/package-lock.json and b/api/package-lock.json differ diff --git a/api/package.json b/api/package.json index 8a0bbdd1..c9dd6b1f 100644 --- a/api/package.json +++ b/api/package.json @@ -5,6 +5,8 @@ "main": "dist/Server.js", "types": "dist/Server.d.ts", "scripts": { + "link": "npm run build && npm link", + "postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link", "test": "jest", "test:watch": "jest --watch", "start": "npm run build && node dist/start", @@ -33,7 +35,7 @@ }, "homepage": "https://github.com/fosscord/fosscord-api#readme", "dependencies": { - "@fosscord/server-util": "file:../util", + "@fosscord/util": "file:../util", "@types/jest": "^26.0.22", "@types/json-schema": "^7.0.7", "ajv": "^8.4.0", diff --git a/api/src/Server.ts b/api/src/Server.ts index 7299425a..a60c5e4d 100644 --- a/api/src/Server.ts +++ b/api/src/Server.ts @@ -3,7 +3,7 @@ import fs from "fs"; import { Connection } from "mongoose"; import { Server, ServerOptions } from "lambert-server"; import { Authentication, CORS } from "./middlewares/"; -import { Config, db, RabbitMQ } from "@fosscord/server-util"; +import { Config, db, initEvent, RabbitMQ } from "@fosscord/util"; import i18next from "i18next"; import i18nextMiddleware, { I18next } from "i18next-http-middleware"; import i18nextBackend from "i18next-node-fs-backend"; @@ -56,9 +56,8 @@ export class FosscordServer extends Server { // @ts-ignore await (db as Promise); await this.setupSchema(); - console.log("[Database] connected"); await Config.init(); - await RabbitMQ.init(); + await initEvent(); this.app.use(CORS); this.app.use(Authentication); @@ -93,11 +92,12 @@ export class FosscordServer extends Server { app.use("/api/v9", api); app.use("/api", api); // allow unversioned requests - api.get("*", (req: Request, res: Response) => { + api.get("*", (req: Request, res: Response, next) => { res.status(404).json({ message: "404: Not Found", code: 0 }); + next(); }); this.app = app; diff --git a/api/src/index.ts b/api/src/index.ts index 554c296f..6037e31f 100644 --- a/api/src/index.ts +++ b/api/src/index.ts @@ -7,9 +7,7 @@ export * from "./schema/Invite"; export * from "./schema/Message"; export * from "./util/Config"; export * from "./util/Constants"; -export * from "./util/Event"; export * from "./util/instanceOf"; -export * from "./util/Event"; export * from "./util/instanceOf"; export * from "./util/Member"; export * from "./util/RandomInviteID"; diff --git a/api/src/middlewares/Authentication.ts b/api/src/middlewares/Authentication.ts index 01b7ef57..00cd9ea7 100644 --- a/api/src/middlewares/Authentication.ts +++ b/api/src/middlewares/Authentication.ts @@ -1,15 +1,15 @@ import { NextFunction, Request, Response } from "express"; import { HTTPError } from "lambert-server"; -import { checkToken, Config } from "@fosscord/server-util"; +import { checkToken, Config } from "@fosscord/util"; export const NO_AUTHORIZATION_ROUTES = [ - /^\/api(\/v\d+)?\/auth\/login/, - /^\/api(\/v\d+)?\/auth\/register/, - /^\/api(\/v\d+)?\/webhooks\//, - /^\/api(\/v\d+)?\/ping/, - /^\/api(\/v\d+)?\/gateway/, - /^\/api(\/v\d+)?\/experiments/, - /^\/api(\/v\d+)?\/guilds\/\d+\/widget\.(json|png)/ + "/auth/login", + "/auth/register", + "/webhooks/", + "/ping", + "/gateway", + "/experiments" + // /^\/api(\/v\d+)?\/guilds\/\d+\/widget\.(json|png)/ ]; export const API_PREFIX = /^\/api(\/v\d+)?/; @@ -24,13 +24,14 @@ declare global { } } } +// TODO wenn client offen ist, wird http://localhost:8080/api/v9/users/@me/guild-events blockiert? export async function Authentication(req: Request, res: Response, next: NextFunction) { if (req.method === "OPTIONS") return res.sendStatus(204); if (!req.url.startsWith("/api")) return next(); const apiPath = req.url.replace(API_PREFIX, ""); - if (apiPath.startsWith("/invites") && req.method === "GET") return next(); - if (NO_AUTHORIZATION_ROUTES.some((x) => x.test(req.url))) return next(); + if (apiPath.startsWith("/invites") && req.method === "GET") return next(); // @ts-ignore + if (NO_AUTHORIZATION_ROUTES.some((x) => apiPath.startsWith(x) || x.test?.(req.url))) return next(); if (!req.headers.authorization) return next(new HTTPError("Missing Authorization Header", 401)); try { diff --git a/api/src/middlewares/ErrorHandler.ts b/api/src/middlewares/ErrorHandler.ts index 2e6b1d8b..04d56026 100644 --- a/api/src/middlewares/ErrorHandler.ts +++ b/api/src/middlewares/ErrorHandler.ts @@ -25,8 +25,6 @@ export function ErrorHandler(error: Error, req: Request, res: Response, next: Ne if (httpcode > 511) httpcode = 400; res.status(httpcode).json({ code: code, message, errors }); - - return; } catch (error) { console.error(error); return res.status(500).json({ code: 500, message: "Internal Server Error" }); diff --git a/api/src/middlewares/RateLimit.ts b/api/src/middlewares/RateLimit.ts index c8fdeba2..a1bb0c44 100644 --- a/api/src/middlewares/RateLimit.ts +++ b/api/src/middlewares/RateLimit.ts @@ -1,16 +1,17 @@ -import { db, MongooseCache, Bucket, Config } from "@fosscord/server-util"; +// @ts-nocheck +import { db, Bucket, Config } from "@fosscord/util"; import { NextFunction, Request, Response, Router } from "express"; import { getIpAdress } from "../util/ipAddress"; import { API_PREFIX_TRAILING_SLASH } from "./Authentication"; -const Cache = new MongooseCache( - db.collection("ratelimits"), - [ - // TODO: uncomment $match and fix error: not receiving change events - // { $match: { blocked: true } } - ], - { onlyEvents: false, array: true } -); +// const Cache = new MongooseCache( +// db.collection("ratelimits"), +// [ +// // TODO: uncomment $match and fix error: not receiving change events +// // { $match: { blocked: true } } +// ], +// { onlyEvents: false, array: true } +// ); // Docs: https://discord.com/developers/docs/topics/rate-limits @@ -31,6 +32,7 @@ TODO: use config values */ +// TODO: FIX with new event handling export default function RateLimit(opts: { bucket?: string; window: number; @@ -44,6 +46,7 @@ export default function RateLimit(opts: { success?: boolean; onlyIp?: boolean; }): any { + return (req, res, next) => next(); Cache.init(); // will only initalize it once return async (req: Request, res: Response, next: NextFunction): Promise => { diff --git a/api/src/routes/auth/login.ts b/api/src/routes/auth/login.ts index c3661608..f55d5351 100644 --- a/api/src/routes/auth/login.ts +++ b/api/src/routes/auth/login.ts @@ -2,7 +2,7 @@ import { Request, Response, Router } from "express"; import { check, FieldErrors, Length } from "../../util/instanceOf"; import bcrypt from "bcrypt"; import jwt from "jsonwebtoken"; -import { Config, UserModel } from "@fosscord/server-util"; +import { Config, UserModel } from "@fosscord/util"; import { adjustEmail } from "./register"; import RateLimit from "../../middlewares/RateLimit"; diff --git a/api/src/routes/auth/register.ts b/api/src/routes/auth/register.ts index 66a1fc8d..fecde874 100644 --- a/api/src/routes/auth/register.ts +++ b/api/src/routes/auth/register.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { trimSpecial, User, Snowflake, UserModel, Config } from "@fosscord/server-util"; +import { trimSpecial, User, Snowflake, UserModel, Config } from "@fosscord/util"; import bcrypt from "bcrypt"; import { check, Email, EMAIL_REGEX, FieldErrors, Length } from "../../util/instanceOf"; import "missing-native-js-functions"; diff --git a/api/src/routes/channels/#channel_id/index.ts b/api/src/routes/channels/#channel_id/index.ts index 81e5054e..3bfa80be 100644 --- a/api/src/routes/channels/#channel_id/index.ts +++ b/api/src/routes/channels/#channel_id/index.ts @@ -1,8 +1,7 @@ -import { ChannelDeleteEvent, ChannelModel, ChannelUpdateEvent, getPermission, GuildUpdateEvent, toObject } from "@fosscord/server-util"; +import { ChannelDeleteEvent, ChannelModel, ChannelUpdateEvent, emitEvent, getPermission, GuildUpdateEvent, toObject } from "@fosscord/util"; import { Router, Response, Request } from "express"; import { HTTPError } from "lambert-server"; import { ChannelModifySchema } from "../../../schema/Channel"; -import { emitEvent } from "../../../util/Event"; import { check } from "../../../util/instanceOf"; const router: Router = Router(); // TODO: delete channel diff --git a/api/src/routes/channels/#channel_id/invites.ts b/api/src/routes/channels/#channel_id/invites.ts index c9db4dd2..438f8c51 100644 --- a/api/src/routes/channels/#channel_id/invites.ts +++ b/api/src/routes/channels/#channel_id/invites.ts @@ -3,11 +3,10 @@ import { HTTPError } from "lambert-server"; import { check } from "../../../util/instanceOf"; import { random } from "../../../util/RandomInviteID"; -import { emitEvent } from "../../../util/Event"; import { InviteCreateSchema } from "../../../schema/Invite"; -import { getPermission, ChannelModel, InviteModel, InviteCreateEvent, toObject } from "@fosscord/server-util"; +import { getPermission, ChannelModel, InviteModel, InviteCreateEvent, toObject, emitEvent } from "@fosscord/util"; const router: Router = Router(); diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts b/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts index f4d9e696..bbc779dd 100644 --- a/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts +++ b/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts @@ -1,6 +1,6 @@ -import { getPermission, MessageAckEvent, ReadStateModel } from "@fosscord/server-util"; +import { emitEvent, getPermission, MessageAckEvent, ReadStateModel } from "@fosscord/util"; import { Request, Response, Router } from "express"; -import { emitEvent } from "../../../../../util/Event"; + import { check } from "../../../../../util/instanceOf"; const router = Router(); diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts index a7c23d2f..3c58d034 100644 --- a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts +++ b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts @@ -1,8 +1,8 @@ -import { ChannelModel, getPermission, MessageDeleteEvent, MessageModel, MessageUpdateEvent, toObject } from "@fosscord/server-util"; +import { ChannelModel, emitEvent, getPermission, MessageDeleteEvent, MessageModel, MessageUpdateEvent, toObject } from "@fosscord/util"; import { Router, Response, Request } from "express"; import { HTTPError } from "lambert-server"; import { MessageCreateSchema } from "../../../../../schema/Message"; -import { emitEvent } from "../../../../../util/Event"; + import { check } from "../../../../../util/instanceOf"; import { handleMessage, postHandleMessage } from "../../../../../util/Message"; diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts b/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts index 168a870f..34d2ce3a 100644 --- a/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts +++ b/api/src/routes/channels/#channel_id/messages/#message_id/reactions.ts @@ -1,5 +1,6 @@ import { ChannelModel, + emitEvent, EmojiModel, getPermission, MemberModel, @@ -12,10 +13,9 @@ import { PublicUserProjection, toObject, UserModel -} from "@fosscord/server-util"; +} from "@fosscord/util"; import { Router, Response, Request } from "express"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../../../util/Event"; const router = Router(); // TODO: check if emoji is really an unicode emoji or a prperly encoded external emoji diff --git a/api/src/routes/channels/#channel_id/messages/bulk-delete.ts b/api/src/routes/channels/#channel_id/messages/bulk-delete.ts index e53cd597..8132462f 100644 --- a/api/src/routes/channels/#channel_id/messages/bulk-delete.ts +++ b/api/src/routes/channels/#channel_id/messages/bulk-delete.ts @@ -1,7 +1,7 @@ import { Router, Response, Request } from "express"; -import { ChannelModel, Config, getPermission, MessageDeleteBulkEvent, MessageModel } from "@fosscord/server-util"; +import { ChannelModel, Config, emitEvent, getPermission, MessageDeleteBulkEvent, MessageModel } from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../../util/Event"; + import { check } from "../../../../util/instanceOf"; const router: Router = Router(); diff --git a/api/src/routes/channels/#channel_id/messages/index.ts b/api/src/routes/channels/#channel_id/messages/index.ts index fea4d6a4..6ae6491f 100644 --- a/api/src/routes/channels/#channel_id/messages/index.ts +++ b/api/src/routes/channels/#channel_id/messages/index.ts @@ -1,5 +1,5 @@ import { Router, Response, Request } from "express"; -import { Attachment, ChannelModel, ChannelType, getPermission, MessageDocument, MessageModel, toObject } from "@fosscord/server-util"; +import { Attachment, ChannelModel, ChannelType, getPermission, MessageDocument, MessageModel, toObject } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { MessageCreateSchema } from "../../../../schema/Message"; import { check, instanceOf, Length } from "../../../../util/instanceOf"; diff --git a/api/src/routes/channels/#channel_id/permissions.ts b/api/src/routes/channels/#channel_id/permissions.ts index 12364293..4cbc7522 100644 --- a/api/src/routes/channels/#channel_id/permissions.ts +++ b/api/src/routes/channels/#channel_id/permissions.ts @@ -1,7 +1,15 @@ -import { ChannelModel, ChannelPermissionOverwrite, ChannelUpdateEvent, getPermission, MemberModel, RoleModel } from "@fosscord/server-util"; +import { + ChannelModel, + ChannelPermissionOverwrite, + ChannelUpdateEvent, + emitEvent, + getPermission, + MemberModel, + RoleModel +} from "@fosscord/util"; import { Router, Response, Request } from "express"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; + import { check } from "../../../util/instanceOf"; const router: Router = Router(); diff --git a/api/src/routes/channels/#channel_id/pins.ts b/api/src/routes/channels/#channel_id/pins.ts index 65d6b975..18a5861b 100644 --- a/api/src/routes/channels/#channel_id/pins.ts +++ b/api/src/routes/channels/#channel_id/pins.ts @@ -2,14 +2,14 @@ import { ChannelModel, ChannelPinsUpdateEvent, Config, + emitEvent, getPermission, MessageModel, MessageUpdateEvent, toObject -} from "@fosscord/server-util"; +} from "@fosscord/util"; import { Router, Request, Response } from "express"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; const router: Router = Router(); diff --git a/api/src/routes/channels/#channel_id/typing.ts b/api/src/routes/channels/#channel_id/typing.ts index de549883..21d453d8 100644 --- a/api/src/routes/channels/#channel_id/typing.ts +++ b/api/src/routes/channels/#channel_id/typing.ts @@ -1,8 +1,7 @@ -import { ChannelModel, MemberModel, toObject, TypingStartEvent } from "@fosscord/server-util"; +import { ChannelModel, emitEvent, MemberModel, toObject, TypingStartEvent } from "@fosscord/util"; import { Router, Request, Response } from "express"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; const router: Router = Router(); diff --git a/api/src/routes/channels/#channel_id/webhooks.ts b/api/src/routes/channels/#channel_id/webhooks.ts index 6c1aea2a..7852f8f3 100644 --- a/api/src/routes/channels/#channel_id/webhooks.ts +++ b/api/src/routes/channels/#channel_id/webhooks.ts @@ -1,6 +1,6 @@ import { Router, Response, Request } from "express"; import { check, Length } from "../../../util/instanceOf"; -import { ChannelModel, getPermission, trimSpecial } from "@fosscord/server-util"; +import { ChannelModel, getPermission, trimSpecial } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { isTextChannel } from "./messages/index"; diff --git a/api/src/routes/gateway.ts b/api/src/routes/gateway.ts index f2bc5b34..3120718e 100644 --- a/api/src/routes/gateway.ts +++ b/api/src/routes/gateway.ts @@ -1,4 +1,4 @@ -import { Config } from "@fosscord/server-util"; +import { Config } from "@fosscord/util"; import { Router, Response, Request } from "express"; const router = Router(); diff --git a/api/src/routes/guilds/#guild_id/bans.ts b/api/src/routes/guilds/#guild_id/bans.ts index d9752f61..bb3eac03 100644 --- a/api/src/routes/guilds/#guild_id/bans.ts +++ b/api/src/routes/guilds/#guild_id/bans.ts @@ -1,9 +1,9 @@ import { Request, Response, Router } from "express"; -import { BanModel, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, GuildModel, toObject } from "@fosscord/server-util"; +import { BanModel, emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, GuildModel, toObject } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { getIpAdress } from "../../../util/ipAddress"; import { BanCreateSchema } from "../../../schema/Ban"; -import { emitEvent } from "../../../util/Event"; + import { check } from "../../../util/instanceOf"; import { removeMember } from "../../../util/Member"; import { getPublicUser } from "../../../util/User"; diff --git a/api/src/routes/guilds/#guild_id/channels.ts b/api/src/routes/guilds/#guild_id/channels.ts index 52361f5e..8d97cf96 100644 --- a/api/src/routes/guilds/#guild_id/channels.ts +++ b/api/src/routes/guilds/#guild_id/channels.ts @@ -8,11 +8,12 @@ import { toObject, ChannelUpdateEvent, AnyChannel, - getPermission -} from "@fosscord/server-util"; + getPermission, + emitEvent +} from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { ChannelModifySchema } from "../../../schema/Channel"; -import { emitEvent } from "../../../util/Event"; + import { check } from "../../../util/instanceOf"; import { createChannel } from "../../../util/Channel"; const router = Router(); @@ -64,7 +65,7 @@ router.patch( const channel = await ChannelModel.findOneAndUpdate({ id: req.body, guild_id }, opts).exec(); - await emitEvent({ event: "CHANNEL_UPDATE", data: channel, channel_id: body.id, guild_id } as ChannelUpdateEvent); + await emitEvent({ event: "CHANNEL_UPDATE", data: toObject(channel), channel_id: body.id, guild_id } as ChannelUpdateEvent); res.json(toObject(channel)); } diff --git a/api/src/routes/guilds/#guild_id/delete.ts b/api/src/routes/guilds/#guild_id/delete.ts index 6cca289e..ba1c2fde 100644 --- a/api/src/routes/guilds/#guild_id/delete.ts +++ b/api/src/routes/guilds/#guild_id/delete.ts @@ -1,5 +1,6 @@ import { ChannelModel, + emitEvent, EmojiModel, GuildDeleteEvent, GuildModel, @@ -8,10 +9,9 @@ import { MessageModel, RoleModel, UserModel -} from "@fosscord/server-util"; +} from "@fosscord/util"; import { Router, Request, Response } from "express"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; const router = Router(); diff --git a/api/src/routes/guilds/#guild_id/index.ts b/api/src/routes/guilds/#guild_id/index.ts index dc4ddb39..1afa603f 100644 --- a/api/src/routes/guilds/#guild_id/index.ts +++ b/api/src/routes/guilds/#guild_id/index.ts @@ -1,6 +1,7 @@ import { Request, Response, Router } from "express"; import { ChannelModel, + emitEvent, EmojiModel, getPermission, GuildDeleteEvent, @@ -12,10 +13,10 @@ import { RoleModel, toObject, UserModel -} from "@fosscord/server-util"; +} from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { GuildUpdateSchema } from "../../../schema/Guild"; -import { emitEvent } from "../../../util/Event"; + import { check } from "../../../util/instanceOf"; import { handleFile } from "../../../util/cdn"; import "missing-native-js-functions"; diff --git a/api/src/routes/guilds/#guild_id/invites.ts b/api/src/routes/guilds/#guild_id/invites.ts index 1894ec96..08048d61 100644 --- a/api/src/routes/guilds/#guild_id/invites.ts +++ b/api/src/routes/guilds/#guild_id/invites.ts @@ -1,4 +1,4 @@ -import { getPermission, InviteModel, toObject } from "@fosscord/server-util"; +import { getPermission, InviteModel, toObject } from "@fosscord/util"; import { Request, Response, Router } from "express"; const router = Router(); diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts index 9a1676e6..eac6684a 100644 --- a/api/src/routes/guilds/#guild_id/members/#member_id/index.ts +++ b/api/src/routes/guilds/#guild_id/members/#member_id/index.ts @@ -8,13 +8,13 @@ import { getPermission, PermissionResolvable, RoleModel, - GuildMemberUpdateEvent -} from "@fosscord/server-util"; + GuildMemberUpdateEvent, + emitEvent +} from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { addMember, isMember, removeMember } from "../../../../../util/Member"; import { check } from "../../../../../util/instanceOf"; import { MemberChangeSchema } from "../../../../../schema/Member"; -import { emitEvent } from "../../../../../util/Event"; const router = Router(); diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/nick.ts b/api/src/routes/guilds/#guild_id/members/#member_id/nick.ts index 9078409d..5784b5d5 100644 --- a/api/src/routes/guilds/#guild_id/members/#member_id/nick.ts +++ b/api/src/routes/guilds/#guild_id/members/#member_id/nick.ts @@ -1,4 +1,4 @@ -import { getPermission, PermissionResolvable } from "@fosscord/server-util"; +import { getPermission, PermissionResolvable } from "@fosscord/util"; import { Request, Response, Router } from "express"; import { check } from "lambert-server"; import { MemberNickChangeSchema } from "../../../../../schema/Member"; diff --git a/api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts b/api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts index b7a43c74..fad0695e 100644 --- a/api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts +++ b/api/src/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts @@ -1,4 +1,4 @@ -import { getPermission } from "@fosscord/server-util"; +import { getPermission } from "@fosscord/util"; import { Request, Response, Router } from "express"; import { addRole, removeRole } from "../../../../../../../util/Member"; diff --git a/api/src/routes/guilds/#guild_id/members/index.ts b/api/src/routes/guilds/#guild_id/members/index.ts index a157d8f5..70303436 100644 --- a/api/src/routes/guilds/#guild_id/members/index.ts +++ b/api/src/routes/guilds/#guild_id/members/index.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { GuildModel, MemberModel, toObject } from "@fosscord/server-util"; +import { GuildModel, MemberModel, toObject } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { instanceOf, Length } from "../../../../util/instanceOf"; import { PublicMemberProjection, isMember } from "../../../../util/Member"; diff --git a/api/src/routes/guilds/#guild_id/regions.ts b/api/src/routes/guilds/#guild_id/regions.ts index 3a46d766..5ec649ee 100644 --- a/api/src/routes/guilds/#guild_id/regions.ts +++ b/api/src/routes/guilds/#guild_id/regions.ts @@ -1,4 +1,4 @@ -import { Config } from "@fosscord/server-util"; +import { Config } from "@fosscord/util"; import { Request, Response, Router } from "express"; const router = Router(); @@ -7,4 +7,4 @@ router.get("/", async (req: Request, res: Response) => { return res.json(Config.get().regions.available); }); -export default router; \ No newline at end of file +export default router; diff --git a/api/src/routes/guilds/#guild_id/roles.ts b/api/src/routes/guilds/#guild_id/roles.ts index 77206a0f..a4bc44e0 100644 --- a/api/src/routes/guilds/#guild_id/roles.ts +++ b/api/src/routes/guilds/#guild_id/roles.ts @@ -9,10 +9,11 @@ import { MemberModel, GuildRoleCreateEvent, GuildRoleUpdateEvent, - GuildRoleDeleteEvent -} from "@fosscord/server-util"; + GuildRoleDeleteEvent, + emitEvent +} from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; + import { check } from "../../../util/instanceOf"; import { RoleModifySchema } from "../../../schema/Roles"; import { getPublicUser } from "../../../util/User"; diff --git a/api/src/routes/guilds/#guild_id/templates.ts b/api/src/routes/guilds/#guild_id/templates.ts index 8306ac37..fdca1c40 100644 --- a/api/src/routes/guilds/#guild_id/templates.ts +++ b/api/src/routes/guilds/#guild_id/templates.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { TemplateModel, GuildModel, getPermission, toObject, UserModel, Snowflake } from "@fosscord/server-util"; +import { TemplateModel, GuildModel, getPermission, toObject, UserModel, Snowflake } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { TemplateCreateSchema, TemplateModifySchema } from "../../../schema/Template"; import { check } from "../../../util/instanceOf"; diff --git a/api/src/routes/guilds/#guild_id/vanity-url.ts b/api/src/routes/guilds/#guild_id/vanity-url.ts index 323b2647..86adfeb0 100644 --- a/api/src/routes/guilds/#guild_id/vanity-url.ts +++ b/api/src/routes/guilds/#guild_id/vanity-url.ts @@ -1,4 +1,4 @@ -import { getPermission, GuildModel, InviteModel, trimSpecial } from "@fosscord/server-util"; +import { getPermission, GuildModel, InviteModel, trimSpecial } from "@fosscord/util"; import { Router, Request, Response } from "express"; import { HTTPError } from "lambert-server"; import { check, Length } from "../../../util/instanceOf"; diff --git a/api/src/routes/guilds/#guild_id/welcome_screen.ts b/api/src/routes/guilds/#guild_id/welcome_screen.ts index 656a0ee0..c717042e 100644 --- a/api/src/routes/guilds/#guild_id/welcome_screen.ts +++ b/api/src/routes/guilds/#guild_id/welcome_screen.ts @@ -1,7 +1,7 @@ import { Request, Response, Router } from "express"; -import { GuildModel, getPermission, toObject, Snowflake } from "@fosscord/server-util"; +import { GuildModel, getPermission, toObject, Snowflake } from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; + import { check } from "../../../util/instanceOf"; import { isMember } from "../../../util/Member"; import { GuildAddChannelToWelcomeScreenSchema } from "../../../schema/Guild"; diff --git a/api/src/routes/guilds/#guild_id/widget.json.ts b/api/src/routes/guilds/#guild_id/widget.json.ts index 6f777ab4..8719bd85 100644 --- a/api/src/routes/guilds/#guild_id/widget.json.ts +++ b/api/src/routes/guilds/#guild_id/widget.json.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { Config, Permissions, GuildModel, InviteModel, ChannelModel, MemberModel } from "@fosscord/server-util"; +import { Config, Permissions, GuildModel, InviteModel, ChannelModel, MemberModel } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { random } from "../../../util/RandomInviteID"; diff --git a/api/src/routes/guilds/#guild_id/widget.png.ts b/api/src/routes/guilds/#guild_id/widget.png.ts index a0a8c938..80dc9f2b 100644 --- a/api/src/routes/guilds/#guild_id/widget.png.ts +++ b/api/src/routes/guilds/#guild_id/widget.png.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { GuildModel } from "@fosscord/server-util"; +import { GuildModel } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import fs from "fs"; import path from "path"; diff --git a/api/src/routes/guilds/#guild_id/widget.ts b/api/src/routes/guilds/#guild_id/widget.ts index 0e6df186..85eed5e9 100644 --- a/api/src/routes/guilds/#guild_id/widget.ts +++ b/api/src/routes/guilds/#guild_id/widget.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { getPermission, GuildModel } from "@fosscord/server-util"; +import { getPermission, GuildModel } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { check } from "../../../util/instanceOf"; import { WidgetModifySchema } from "../../../schema/Widget"; diff --git a/api/src/routes/guilds/index.ts b/api/src/routes/guilds/index.ts index 25b55896..c97a8205 100644 --- a/api/src/routes/guilds/index.ts +++ b/api/src/routes/guilds/index.ts @@ -1,5 +1,5 @@ import { Router, Request, Response } from "express"; -import { RoleModel, GuildModel, Snowflake, Guild, RoleDocument, Config } from "@fosscord/server-util"; +import { RoleModel, GuildModel, Snowflake, Guild, RoleDocument, Config } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { check } from "./../../util/instanceOf"; import { GuildCreateSchema } from "../../schema/Guild"; diff --git a/api/src/routes/guilds/templates/index.ts b/api/src/routes/guilds/templates/index.ts index 0f332de0..7fed3c5d 100644 --- a/api/src/routes/guilds/templates/index.ts +++ b/api/src/routes/guilds/templates/index.ts @@ -1,6 +1,6 @@ import { Request, Response, Router } from "express"; const router: Router = Router(); -import { TemplateModel, GuildModel, toObject, UserModel, RoleModel, Snowflake, Guild, Config } from "@fosscord/server-util"; +import { TemplateModel, GuildModel, toObject, UserModel, RoleModel, Snowflake, Guild, Config } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { GuildTemplateCreateSchema } from "../../../schema/Guild"; import { getPublicUser } from "../../../util/User"; diff --git a/api/src/routes/invites/index.ts b/api/src/routes/invites/index.ts index 8c04713c..992694df 100644 --- a/api/src/routes/invites/index.ts +++ b/api/src/routes/invites/index.ts @@ -1,5 +1,5 @@ import { Router, Request, Response } from "express"; -import { getPermission, InviteModel, toObject } from "@fosscord/server-util"; +import { getPermission, InviteModel, toObject } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { addMember } from "../../util/Member"; const router: Router = Router(); diff --git a/api/src/routes/users/@me/channels.ts b/api/src/routes/users/@me/channels.ts index a425a25f..db9f8832 100644 --- a/api/src/routes/users/@me/channels.ts +++ b/api/src/routes/users/@me/channels.ts @@ -8,10 +8,11 @@ import { trimSpecial, Channel, DMChannel, - UserModel -} from "@fosscord/server-util"; + UserModel, + emitEvent +} from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; + import { DmChannelCreateSchema } from "../../../schema/Channel"; import { check } from "../../../util/instanceOf"; diff --git a/api/src/routes/users/@me/delete.ts b/api/src/routes/users/@me/delete.ts index edda8e2d..f863237d 100644 --- a/api/src/routes/users/@me/delete.ts +++ b/api/src/routes/users/@me/delete.ts @@ -1,5 +1,5 @@ import { Router, Request, Response } from "express"; -import { GuildModel, MemberModel, UserModel } from "@fosscord/server-util"; +import { GuildModel, MemberModel, UserModel } from "@fosscord/util"; import bcrypt from "bcrypt"; const router = Router(); diff --git a/api/src/routes/users/@me/disable.ts b/api/src/routes/users/@me/disable.ts index 0e5b734e..2d3a9850 100644 --- a/api/src/routes/users/@me/disable.ts +++ b/api/src/routes/users/@me/disable.ts @@ -1,4 +1,4 @@ -import { UserModel } from "@fosscord/server-util"; +import { UserModel } from "@fosscord/util"; import { Router, Response, Request } from "express"; import bcrypt from "bcrypt"; diff --git a/api/src/routes/users/@me/guilds.ts b/api/src/routes/users/@me/guilds.ts index 6528552b..a9b53b75 100644 --- a/api/src/routes/users/@me/guilds.ts +++ b/api/src/routes/users/@me/guilds.ts @@ -1,7 +1,7 @@ import { Router, Request, Response } from "express"; -import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent, toObject } from "@fosscord/server-util"; +import { GuildModel, MemberModel, UserModel, GuildDeleteEvent, GuildMemberRemoveEvent, toObject, emitEvent } from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; + import { getPublicUser } from "../../../util/User"; const router: Router = Router(); @@ -32,10 +32,10 @@ router.delete("/:id", async (req: Request, res: Response) => { emitEvent({ event: "GUILD_DELETE", data: { - id: guild_id, + id: guild_id }, - user_id: req.user_id, - } as GuildDeleteEvent), + user_id: req.user_id + } as GuildDeleteEvent) ]); const user = await getPublicUser(req.user_id); @@ -44,9 +44,9 @@ router.delete("/:id", async (req: Request, res: Response) => { event: "GUILD_MEMBER_REMOVE", data: { guild_id: guild_id, - user: user, + user: user }, - guild_id: guild_id, + guild_id: guild_id } as GuildMemberRemoveEvent); return res.sendStatus(204); diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts index 7bd4a486..c073e78a 100644 --- a/api/src/routes/users/@me/index.ts +++ b/api/src/routes/users/@me/index.ts @@ -1,5 +1,5 @@ import { Router, Request, Response } from "express"; -import { UserModel, toObject, PublicUserProjection } from "@fosscord/server-util"; +import { UserModel, toObject, PublicUserProjection } from "@fosscord/util"; import { getPublicUser } from "../../../util/User"; import { UserModifySchema } from "../../../schema/User"; import { check } from "../../../util/instanceOf"; diff --git a/api/src/routes/users/@me/relationships.ts b/api/src/routes/users/@me/relationships.ts index a8f03143..642ee5f9 100644 --- a/api/src/routes/users/@me/relationships.ts +++ b/api/src/routes/users/@me/relationships.ts @@ -5,11 +5,12 @@ import { toObject, RelationshipType, RelationshipRemoveEvent, - UserDocument -} from "@fosscord/server-util"; + UserDocument, + emitEvent +} from "@fosscord/util"; import { Router, Response, Request } from "express"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "../../../util/Event"; + import { check, Length } from "../../../util/instanceOf"; const router = Router(); diff --git a/api/src/schema/Channel.ts b/api/src/schema/Channel.ts index 48c3a1d2..18a8f835 100644 --- a/api/src/schema/Channel.ts +++ b/api/src/schema/Channel.ts @@ -1,4 +1,4 @@ -import { ChannelType } from "@fosscord/server-util"; +import { ChannelType } from "@fosscord/util"; import { Length } from "../util/instanceOf"; export const ChannelModifySchema = { diff --git a/api/src/schema/Guild.ts b/api/src/schema/Guild.ts index 0443e64c..ce40b49f 100644 --- a/api/src/schema/Guild.ts +++ b/api/src/schema/Guild.ts @@ -1,4 +1,4 @@ -import { ChannelSchema, GuildChannel } from "@fosscord/server-util"; +import { ChannelSchema, GuildChannel } from "@fosscord/util"; import { Length } from "../util/instanceOf"; export const GuildCreateSchema = { diff --git a/api/src/schema/Message.ts b/api/src/schema/Message.ts index 8423d706..2dd54f0c 100644 --- a/api/src/schema/Message.ts +++ b/api/src/schema/Message.ts @@ -1,4 +1,4 @@ -import { Embed, EmbedImage } from "@fosscord/server-util"; +import { Embed, EmbedImage } from "@fosscord/util"; import { Length } from "../util/instanceOf"; export const MessageCreateSchema = { diff --git a/api/src/test/test.ts b/api/src/test/test.ts index 478edcc4..c37c762b 100644 --- a/api/src/test/test.ts +++ b/api/src/test/test.ts @@ -1,3 +1,3 @@ -import { Snowflake } from "@fosscord/server-util"; +import { Snowflake } from "@fosscord/util"; console.log(Snowflake.deconstruct("0")); diff --git a/api/src/util/Channel.ts b/api/src/util/Channel.ts index 4d322812..ef04d521 100644 --- a/api/src/util/Channel.ts +++ b/api/src/util/Channel.ts @@ -2,18 +2,18 @@ import { ChannelCreateEvent, ChannelModel, ChannelType, + emitEvent, getPermission, GuildModel, Snowflake, TextChannel, + toObject, VoiceChannel -} from "@fosscord/server-util"; +} from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "./Event"; // TODO: DM channel export async function createChannel(channel: Partial, user_id: string = "0") { - // Always check if user has permission first const permissions = await getPermission(user_id, channel.guild_id); permissions.hasThrow("MANAGE_CHANNELS"); @@ -50,7 +50,7 @@ export async function createChannel(channel: Partial recipient_ids: null }).save(); - await emitEvent({ event: "CHANNEL_CREATE", data: channel, guild_id: channel.guild_id } as ChannelCreateEvent); + await emitEvent({ event: "CHANNEL_CREATE", data: toObject(channel), guild_id: channel.guild_id } as ChannelCreateEvent); return channel; } diff --git a/api/src/util/Config.ts b/api/src/util/Config.ts index e2e0d312..c86afbe7 100644 --- a/api/src/util/Config.ts +++ b/api/src/util/Config.ts @@ -1,7 +1,7 @@ // @ts-nocheck import Ajv, { JSONSchemaType } from "ajv"; -import { getConfigPathForFile } from "@fosscord/server-util/dist/util/Config"; -import { Config } from "@fosscord/server-util"; +import { getConfigPathForFile } from "@fosscord/util/dist/util/Config"; +import { Config } from "@fosscord/util"; export interface RateLimitOptions { count: number; diff --git a/api/src/util/Event.ts b/api/src/util/Event.ts deleted file mode 100644 index 4dd56417..00000000 --- a/api/src/util/Event.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Config, Event, EventModel, RabbitMQ } from "@fosscord/server-util"; - -export async function emitEvent(payload: Omit) { - if (RabbitMQ.connection) { - const id = (payload.channel_id || payload.user_id || payload.guild_id) as string; - if (!id) console.error("event doesn't contain any id", payload); - const data = typeof payload.data === "object" ? JSON.stringify(payload.data) : payload.data; // use rabbitmq for event transmission - await RabbitMQ.channel?.assertExchange(id, "fanout", { durable: false }); - - // assertQueue isn't needed, because a queue will automatically created if it doesn't exist - const successful = RabbitMQ.channel?.publish(id, "", Buffer.from(`${data}`), { type: payload.event }); - if (!successful) throw new Error("failed to send event"); - } else { - // use mongodb for event transmission - // TODO: use event emitter for local server bundle - const obj = { - created_at: new Date(), // in seconds - ...payload - }; - // TODO: bigint isn't working - - return await new EventModel(obj).save(); - } -} - -export async function emitAuditLog(payload: any) {} diff --git a/api/src/util/Member.ts b/api/src/util/Member.ts index 7b06720b..ee3f64ad 100644 --- a/api/src/util/Member.ts +++ b/api/src/util/Member.ts @@ -11,11 +11,12 @@ import { toObject, UserModel, GuildDocument, - Config -} from "@fosscord/server-util"; + Config, + emitEvent +} from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { emitEvent } from "./Event"; + import { getPublicUser } from "./User"; export const PublicMemberProjection = { diff --git a/api/src/util/Message.ts b/api/src/util/Message.ts index e811f522..a55c3365 100644 --- a/api/src/util/Message.ts +++ b/api/src/util/Message.ts @@ -1,14 +1,14 @@ -import { ChannelModel, Embed, Message, MessageCreateEvent, MessageUpdateEvent } from "@fosscord/server-util"; -import { Snowflake } from "@fosscord/server-util"; -import { MessageModel } from "@fosscord/server-util"; -import { PublicMemberProjection } from "@fosscord/server-util"; -import { toObject } from "@fosscord/server-util"; -import { getPermission } from "@fosscord/server-util"; +import { ChannelModel, Embed, emitEvent, Message, MessageCreateEvent, MessageUpdateEvent } from "@fosscord/util"; +import { Snowflake } from "@fosscord/util"; +import { MessageModel } from "@fosscord/util"; +import { PublicMemberProjection } from "@fosscord/util"; +import { toObject } from "@fosscord/util"; +import { getPermission } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import fetch from "node-fetch"; import cheerio from "cheerio"; -import { emitEvent } from "./Event"; -import { MessageType } from "@fosscord/server-util/dist/util/Constants"; + +import { MessageType } from "@fosscord/util/dist/util/Constants"; // TODO: check webhook, application, system author const LINK_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g; diff --git a/api/src/util/User.ts b/api/src/util/User.ts index 107fc759..392c7101 100644 --- a/api/src/util/User.ts +++ b/api/src/util/User.ts @@ -1,4 +1,4 @@ -import { toObject, UserModel, PublicUserProjection } from "@fosscord/server-util"; +import { toObject, UserModel, PublicUserProjection } from "@fosscord/util"; import { HTTPError } from "lambert-server"; export { PublicUserProjection }; diff --git a/api/src/util/cdn.ts b/api/src/util/cdn.ts index aed8ca0a..3c71d980 100644 --- a/api/src/util/cdn.ts +++ b/api/src/util/cdn.ts @@ -1,4 +1,4 @@ -import { Config } from "@fosscord/server-util"; +import { Config } from "@fosscord/util"; import FormData from "form-data"; import { HTTPError } from "lambert-server"; import fetch from "node-fetch"; diff --git a/api/src/util/ipAddress.ts b/api/src/util/ipAddress.ts index f2c8fd4d..0a724daa 100644 --- a/api/src/util/ipAddress.ts +++ b/api/src/util/ipAddress.ts @@ -1,4 +1,4 @@ -import { Config } from "@fosscord/server-util"; +import { Config } from "@fosscord/util"; import { Request } from "express"; // use ipdata package instead of simple fetch because of integrated caching import fetch from "node-fetch"; diff --git a/api/src/util/passwordStrength.ts b/api/src/util/passwordStrength.ts index cc503843..dfffa2c0 100644 --- a/api/src/util/passwordStrength.ts +++ b/api/src/util/passwordStrength.ts @@ -1,4 +1,4 @@ -import { Config } from "@fosscord/server-util"; +import { Config } from "@fosscord/util"; import "missing-native-js-functions"; const reNUMBER = /[0-9]/g; diff --git a/bundle/package-lock.json b/bundle/package-lock.json new file mode 100644 index 00000000..8f012973 Binary files /dev/null and b/bundle/package-lock.json differ diff --git a/bundle/package.json b/bundle/package.json new file mode 100644 index 00000000..f4188565 --- /dev/null +++ b/bundle/package.json @@ -0,0 +1,42 @@ +{ + "name": "@fosscord/server", + "version": "1.0.0", + "description": "", + "main": "src/start.js", + "scripts": { + "linkInstall": "npm run --prefix ../util/ link && npm run --prefix ../api/ link && npm run --prefix ../cdn/ link && npm run --prefix ../gateway/ link", + "postinstall": "npm run linkInstall && npm link @fosscord/util && npm link @fosscord/api && npm link @fosscord/gateway && npm link @fosscord/cdn", + "build": "tsc -b .", + "start": "npm run build && node dist/start.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/fosscord/fosscord-api.git" + }, + "keywords": [], + "author": "Fosscord", + "license": "AGPLV3", + "bugs": { + "url": "https://github.com/fosscord/fosscord-api/issues" + }, + "homepage": "https://github.com/fosscord/fosscord-api#readme", + "devDependencies": { + "@types/async-exit-hook": "^2.0.0", + "@types/express": "^4.17.13", + "@types/node": "^16.6.1", + "@types/node-os-utils": "^1.2.0", + "typescript": "^4.3.5" + }, + "dependencies": { + "@fosscord/api": "file:../api", + "@fosscord/cdn": "file:../cdn", + "@fosscord/gateway": "file:../gateway", + "@fosscord/util": "file:../util", + "async-exit-hook": "^2.0.1", + "express": "^4.17.1", + "link": "^0.1.5", + "mongodb-memory-server-global-4.4": "^7.3.6", + "node-os-utils": "^1.3.5" + } +} diff --git a/bundle/src/Server.ts b/bundle/src/Server.ts new file mode 100644 index 00000000..14abc128 --- /dev/null +++ b/bundle/src/Server.ts @@ -0,0 +1,33 @@ +process.on("unhandledRejection", console.error); +process.on("uncaughtException", console.error); + +import http from "http"; +import { FosscordServer as APIServer } from "@fosscord/api"; +import { Server as GatewayServer } from "@fosscord/gateway"; +import { CDNServer } from "@fosscord/cdn/"; +import express from "express"; +import { Config } from "../../util/dist"; + +const app = express(); +const server = http.createServer(); +const port = Number(process.env.PORT) || 8080; +const production = true; +server.on("request", app); + +// @ts-ignore +const api = new APIServer({ server, port, production, app }); +// @ts-ignore +const cdn = new CDNServer({ server, port, production, app }); +// @ts-ignore +const gateway = new GatewayServer({ server, port, production }); + +async function main() { + await api.start(); + await cdn.start(); + await gateway.start(); + + if (!Config.get().gateway.endpoint) await Config.set({ gateway: { endpoint: `ws://localhost:${port}` } }); + if (!Config.get().cdn.endpoint) await Config.set({ cdn: { endpoint: `http://localhost:${port}` } }); +} + +main().catch(console.error); diff --git a/bundle/src/start.ts b/bundle/src/start.ts new file mode 100644 index 00000000..2ae2ce87 --- /dev/null +++ b/bundle/src/start.ts @@ -0,0 +1,74 @@ +import fs from "fs"; +import { MongoMemoryServer } from "mongodb-memory-server-global-4.4"; +import path from "path"; +import cluster from "cluster"; +import os from "os"; +import osu from "node-os-utils"; +import exitHook from "async-exit-hook"; + +const cores = Number(process.env.threads) || 1 || os.cpus().length; + +if (cluster.isMaster && !process.env.masterStarted) { + const dbPath = path.join(__dirname, "..", "..", "db"); + const dbName = "fosscord"; + const storageEngine = "wiredTiger"; + const port = 27020; + const ip = "127.0.0.1"; + var mongod: MongoMemoryServer; + fs.mkdirSync(dbPath, { recursive: true }); + + exitHook((callback: any) => { + (async () => { + console.log(`Stopping MongoDB ...`); + await mongod.stop(); + console.log(`Stopped MongoDB`); + callback(); + })(); + }); + + process.env.masterStarted = "true"; + + setInterval(async () => { + const [cpuUsed, memory, network] = await Promise.all([osu.cpu.usage(), osu.mem.info(), osu.netstat.inOut()]); + if (typeof network === "object") { + console.log(`Network: in ${network.total.inputMb}mb | out ${network.total.outputMb}mb`); + } + + console.log( + `[CPU] ${cpuUsed.toFixed(2)}% | [Memory] ${memory.usedMemMb.toFixed(0)}mb/${memory.totalMemMb.toFixed(0)}mb` + ); + }, 1000 * 60); + + (async () => { + console.log(`[Database] starting ...`); + mongod = new MongoMemoryServer({ + instance: { + port, + ip, + dbName, + dbPath, + storageEngine, + auth: false, // by default `mongod` is started with '--noauth', start `mongod` with '--auth' + }, + }); + await mongod.start(); + process.env.MONGO_URL = mongod.getUri(dbName); + + console.log(`[CPU] ${osu.cpu.model()} Cores x${osu.cpu.count()}`); + console.log(`[System] ${await osu.os.oos()} ${os.arch()}`); + console.log(`[Database] started`); + console.log(`[Process] running with pid: ${process.pid}`); + + // Fork workers. + for (let i = 0; i < cores; i++) { + cluster.fork(); + } + + cluster.on("exit", (worker: any, code: any, signal: any) => { + console.log(`[Worker] died with pid: ${worker.process.pid} , restarting ...`); + cluster.fork(); + }); + })(); +} else { + require("./Server.js"); +} diff --git a/rtc/tsconfig.json b/bundle/tsconfig.json similarity index 94% rename from rtc/tsconfig.json rename to bundle/tsconfig.json index 520774d3..6bf2e6b7 100644 --- a/rtc/tsconfig.json +++ b/bundle/tsconfig.json @@ -5,7 +5,7 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, "lib": ["ES2020"] /* Specify library files to be included in the compilation. */, "allowJs": true /* Allow javascript files to be compiled. */, @@ -43,8 +43,6 @@ /* Module Resolution Options */ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ "types": ["node"] /* Type declaration files to be included in compilation. */, diff --git a/cdn/package.json b/cdn/package.json index 47dc6afa..21976809 100644 --- a/cdn/package.json +++ b/cdn/package.json @@ -5,6 +5,8 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { + "link": "npm run build && npm link", + "postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link", "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc -b .", "start": "npm run build && node dist/start.js" @@ -21,7 +23,7 @@ }, "homepage": "https://github.com/discord-open-source/discord-cdn#readme", "dependencies": { - "@fosscord/server-util": "file:../util", + "@fosscord/util": "file:../util", "body-parser": "^1.19.0", "btoa": "^1.2.1", "cheerio": "^1.0.0-rc.5", diff --git a/cdn/src/Server.ts b/cdn/src/Server.ts index 1b79b037..a73a948c 100644 --- a/cdn/src/Server.ts +++ b/cdn/src/Server.ts @@ -1,5 +1,5 @@ import { Server, ServerOptions } from "lambert-server"; -import { Config, db } from "@fosscord/server-util"; +import { Config, db } from "@fosscord/util"; import path from "path"; import avatarsRoute from "./routes/avatars"; @@ -13,11 +13,9 @@ export class CDNServer extends Server { } async start() { - console.log("[Database] connecting ..."); // @ts-ignore await (db as Promise); await Config.init(); - console.log("[Database] connected"); this.app.use((req, res, next) => { res.set("Access-Control-Allow-Origin", "*"); // TODO: use better CSP policy @@ -33,31 +31,31 @@ export class CDNServer extends Server { await this.registerRoutes(path.join(__dirname, "routes/")); this.app.use("/icons/", avatarsRoute); - this.log("info", "[Server] Route /icons registered"); + this.log("verbose", "[Server] Route /icons registered"); this.app.use("/emojis/", avatarsRoute); - this.log("info", "[Server] Route /emojis registered"); + this.log("verbose", "[Server] Route /emojis registered"); this.app.use("/stickers/", avatarsRoute); - this.log("info", "[Server] Route /stickers registered"); + this.log("verbose", "[Server] Route /stickers registered"); this.app.use("/banners/", avatarsRoute); - this.log("info", "[Server] Route /banners registered"); - + this.log("verbose", "[Server] Route /banners registered"); + this.app.use("/splashes/", avatarsRoute); - this.log("info", "[Server] Route /splashes registered"); + this.log("verbose", "[Server] Route /splashes registered"); this.app.use("/app-icons/", avatarsRoute); - this.log("info", "[Server] Route /app-icons registered"); + this.log("verbose", "[Server] Route /app-icons registered"); this.app.use("/app-assets/", avatarsRoute); - this.log("info", "[Server] Route /app-assets registered"); + this.log("verbose", "[Server] Route /app-assets registered"); this.app.use("/discover-splashes/", avatarsRoute); - this.log("info", "[Server] Route /discover-splashes registered"); + this.log("verbose", "[Server] Route /discover-splashes registered"); this.app.use("/team-icons/", avatarsRoute); - this.log("info", "[Server] Route /team-icons registered"); + this.log("verbose", "[Server] Route /team-icons registered"); return super.start(); } diff --git a/cdn/src/routes/attachments.ts b/cdn/src/routes/attachments.ts index c387aa37..6ce64ed4 100644 --- a/cdn/src/routes/attachments.ts +++ b/cdn/src/routes/attachments.ts @@ -1,5 +1,5 @@ import { Router, Response, Request } from "express"; -import { Config, Snowflake } from "@fosscord/server-util"; +import { Config, Snowflake } from "@fosscord/util"; import { storage } from "../util/Storage"; import FileType from "file-type"; import { HTTPError } from "lambert-server"; diff --git a/cdn/src/routes/avatars.ts b/cdn/src/routes/avatars.ts index 60befe2c..03388afc 100644 --- a/cdn/src/routes/avatars.ts +++ b/cdn/src/routes/avatars.ts @@ -1,5 +1,5 @@ import { Router, Response, Request } from "express"; -import { Config, Snowflake } from "@fosscord/server-util"; +import { Config, Snowflake } from "@fosscord/util"; import { storage } from "../util/Storage"; import FileType from "file-type"; import { HTTPError } from "lambert-server"; diff --git a/cdn/src/routes/external.ts b/cdn/src/routes/external.ts index 3abe9c22..625b6bbd 100644 --- a/cdn/src/routes/external.ts +++ b/cdn/src/routes/external.ts @@ -4,7 +4,7 @@ import { Router, Response, Request } from "express"; import fetch from "node-fetch"; import crypto from "crypto"; import { HTTPError } from "lambert-server"; -import { Snowflake } from "@fosscord/server-util"; +import { Snowflake } from "@fosscord/util"; import { storage } from "../util/Storage"; const router = Router(); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..5861e12f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: "3" +services: + db: + hostname: fosscord_db + image: mongo:latest + volumes: + - ./db:/data/db + restart: unless-stopped + api: + hostname: fosscord_api + image: fosscord/api + depends_on: + - db + ports: + - 3001:3001 + env_file: ./.docker/env + gateway: + hostname: fosscord_gateway + image: fosscord/gateway + depends_on: + - db + ports: + - 3002:3002 + env_file: ./.docker/env \ No newline at end of file diff --git a/gateway/.github/workflows/docker-publish.yml b/gateway/.github/workflows/docker-publish.yml deleted file mode 100644 index 46d9d04d..00000000 --- a/gateway/.github/workflows/docker-publish.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: docker-publish - -on: - push: - branches: - - 'master' - -jobs: - docker: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - push: true - tags: ${{ secrets.DOCKERHUB_TAGS }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new - - - # Hackfix to cleanup cache; replace after buildx 0.6 and BuildKit 0.9 are released - # https://github.com/docker/build-push-action/pull/406#issuecomment-879184394 - name: Move cache fix - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/gateway/package.json b/gateway/package.json index 8f0bb62b..e6c45427 100644 --- a/gateway/package.json +++ b/gateway/package.json @@ -4,16 +4,18 @@ "description": "", "main": "dist/index.js", "scripts": { + "link": "npm run build && npm link", + "postinstall": "npm run --prefix ../util/ link && npm link @fosscord/util && npm run link", "test": "echo \"Error: no test specified\" && exit 1", "start": "npm run build && node dist/start.js", - "build": "npx tsc -b .", + "build": "tsc -b .", "dev": "tsnd --respawn src/start.ts" }, "keywords": [], "author": "Fosscord", "license": "ISC", "dependencies": { - "@fosscord/server-util": "file:../util", + "@fosscord/util": "file:../util", "ajv": "^8.5.0", "amqplib": "^0.8.0", "dotenv": "^8.2.0", diff --git a/gateway/src/Server.ts b/gateway/src/Server.ts index d4b3271c..482545f1 100644 --- a/gateway/src/Server.ts +++ b/gateway/src/Server.ts @@ -1,7 +1,7 @@ import "missing-native-js-functions"; import dotenv from "dotenv"; dotenv.config(); -import { Config, db, RabbitMQ } from "@fosscord/server-util"; +import { Config, db, initEvent, RabbitMQ } from "@fosscord/util"; import { Server as WebSocketServer } from "ws"; import { Connection } from "./events/Connection"; import http from "http"; @@ -40,8 +40,7 @@ export class Server { await (db as Promise); await this.setupSchema(); await Config.init(); - await RabbitMQ.init(); - console.log("[Database] connected"); + await initEvent(); if (!this.server.listening) { this.server.listen(this.port); console.log(`[Gateway] online on 0.0.0.0:${this.port}`); diff --git a/gateway/src/events/Connection.ts b/gateway/src/events/Connection.ts index 1ef9fb48..5fbcbff5 100644 --- a/gateway/src/events/Connection.ts +++ b/gateway/src/events/Connection.ts @@ -40,6 +40,7 @@ export async function Connection(this: Server, socket: WebSocket, request: Incom socket.deflate.on("data", (chunk) => socket.send(chunk)); } + socket.events = {}; socket.permissions = {}; socket.sequence = 0; diff --git a/gateway/src/listener/listener.ts b/gateway/src/listener/listener.ts index 6a6967d6..708bfe5c 100644 --- a/gateway/src/listener/listener.ts +++ b/gateway/src/listener/listener.ts @@ -1,63 +1,31 @@ import { db, Event, - MongooseCache, UserModel, getPermission, Permissions, ChannelModel, RabbitMQ, EVENT, -} from "@fosscord/server-util"; + listenEvent, + EventOpts, + ListenEventOpts, +} from "@fosscord/util"; import { OPCODES } from "../util/Constants"; import { Send } from "../util/Send"; import WebSocket from "../util/WebSocket"; import "missing-native-js-functions"; import { ConsumeMessage } from "amqplib"; +import { Channel } from "amqplib"; // TODO: close connection on Invalidated Token // TODO: check intent // TODO: Guild Member Update is sent for current-user updates regardless of whether the GUILD_MEMBERS intent is set. -// ? How to resubscribe MongooseCache for new dm channel events? Maybe directly send them to the user_id regardless of the channel_id? -> max overhead of creating 10 events in database for dm user group. Or a new field in event -> recipient_ids? // Sharding: calculate if the current shard id matches the formula: shard_id = (guild_id >> 22) % num_shards // https://discord.com/developers/docs/topics/gateway#sharding -export interface DispatchOpts { - eventStream: MongooseCache; - guilds: Array; -} - -function getPipeline(this: WebSocket, guilds: string[], channels: string[] = []) { - if (this.shard_count) { - guilds = guilds.filter((x) => (BigInt(x) >> 22n) % this.shard_count! === this.shard_id); - } - - return [ - { - $match: { - $or: [ - { "fullDocument.guild_id": { $in: guilds } }, - { "fullDocument.user_id": this.user_id }, - { "fullDocument.channel_id": { $in: channels } }, - ], - }, - }, - ]; -} - -async function rabbitListen(this: WebSocket, id: string) { - await this.rabbitCh!.assertExchange(id, "fanout", { durable: false }); - const q = await this.rabbitCh!.assertQueue("", { exclusive: true, autoDelete: true }); - - this.rabbitCh!.bindQueue(q.queue, id, ""); - this.rabbitCh!.consume(q.queue, consume.bind(this), { - noAck: false, - }); - this.rabbitCh!.queues[id] = q.queue; -} - -// TODO: use already required guilds/channels of Identify and don't fetch them again +// TODO: use already queried guilds/channels of Identify and don't fetch them again export async function setupListener(this: WebSocket) { const user = await UserModel.findOne({ id: this.user_id }, { guilds: true }).exec(); const channels = await ChannelModel.find( @@ -67,90 +35,77 @@ export async function setupListener(this: WebSocket) { const dm_channels = channels.filter((x) => !x.guild_id); const guild_channels = channels.filter((x) => x.guild_id); + const opts: { acknowledge: boolean; channel?: Channel } = { acknowledge: true }; + const consumer = consume.bind(this); + if (RabbitMQ.connection) { + opts.channel = await RabbitMQ.connection.createChannel(); // @ts-ignore - this.rabbitCh = await RabbitMQ.connection.createChannel(); - this.rabbitCh!.queues = {}; - - rabbitListen.call(this, this.user_id); - - for (const channel of dm_channels) { - rabbitListen.call(this, channel.id); - } - for (const guild of user.guilds) { - // contains guild and dm channels - - getPermission(this.user_id, guild) - .then((x) => { - this.permissions[guild] = x; - rabbitListen.call(this, guild); - for (const channel of guild_channels) { - if (x.overwriteChannel(channel.permission_overwrites).has("VIEW_CHANNEL")) { - rabbitListen.call(this, channel.id); - } - } - }) - .catch((e) => {}); - } - - this.once("close", () => { - this.rabbitCh!.close(); - }); - } else { - const eventStream = new MongooseCache( - db.collection("events"), - getPipeline.call( - this, - user.guilds, - channels.map((x) => x.id) - ), - { - onlyEvents: true, - } - ); - - await eventStream.init(); - eventStream.on("insert", (document: Event) => - dispatch.call(this, document, { eventStream, guilds: user.guilds }) - ); - - this.once("close", () => eventStream.destroy()); + opts.channel.queues = {}; } + + this.events[this.user_id] = await listenEvent(this.user_id, consumer, opts); + + for (const channel of dm_channels) { + this.events[channel.id] = await listenEvent(channel.id, consumer, opts); + } + + for (const guild of user.guilds) { + // contains guild and dm channels + + getPermission(this.user_id, guild) + .then(async (x) => { + this.permissions[guild] = x; + this.listeners; + this.events[guild] = await listenEvent(guild, consumer, opts); + for (const channel of guild_channels) { + if (x.overwriteChannel(channel.permission_overwrites).has("VIEW_CHANNEL")) { + this.events[channel.id] = await listenEvent(channel.id, consumer, opts); + } + } + }) + .catch((e) => {}); + } + + this.once("close", () => { + if (opts.channel) opts.channel.close(); + else Object.values(this.events).forEach((x) => x()); + }); } -// TODO: use rabbitmq to only receive events that are included in intents -function consume(this: WebSocket, opts: ConsumeMessage | null) { - if (!opts) return; - if (!this.rabbitCh) return; - const data = JSON.parse(opts.content.toString()); +// TODO: only subscribe for events that are in the connection intents +function consume(this: WebSocket, opts: EventOpts) { + const { data, event } = opts; const id = data.id as string; - const event = opts.properties.type as EVENT; const permission = this.permissions[id] || new Permissions("ADMINISTRATOR"); // default permission for dm - console.log("rabbitmq event", event); + const consumer = consume.bind(this); + const listenOpts = opts as ListenEventOpts; + console.log("event", event); // subscription managment switch (event) { case "CHANNEL_DELETE": case "GUILD_DELETE": - this.rabbitCh.cancel(id); + delete this.events[id]; + opts.cancel(); break; case "CHANNEL_CREATE": + if (!permission.overwriteChannel(data.permission_overwrites).has("VIEW_CHANNEL")) return; // TODO: check if user has permission to channel case "GUILD_CREATE": - rabbitListen.call(this, id); + listenEvent(id, consumer, listenOpts); break; case "CHANNEL_UPDATE": - const queue_id = this.rabbitCh.queues[id]; + const exists = this.events[id]; // @ts-ignore - const exists = this.rabbitCh.consumers[id]; if (permission.overwriteChannel(data.permission_overwrites).has("VIEW_CHANNEL")) { if (exists) break; - rabbitListen.call(this, id); + listenEvent(id, consumer, listenOpts); } else { - if (!exists) break; - this.rabbitCh.cancel(queue_id); - this.rabbitCh.unbindQueue(queue_id, id, ""); + if (!exists) return; // return -> do not send channel update events for hidden channels + opts.cancel(id); + delete this.events[id]; } break; } @@ -216,167 +171,5 @@ function consume(this: WebSocket, opts: ConsumeMessage | null) { d: data, s: this.sequence++, }); - this.rabbitCh.ack(opts); -} - -// TODO: cache permission -// we shouldn't fetch the permission for every event, as a message send event with many channel members would result in many thousand db queries. -// instead we should calculate all (guild, channel) permissions once and dynamically update if it changes. -// TODO: only subscribe for events that are in the connection intents -// TODO: only subscribe for channel/guilds that the user has access to (and re-subscribe if it changes) - -export async function dispatch(this: WebSocket, document: Event, { eventStream, guilds }: DispatchOpts) { - var permission = new Permissions("ADMINISTRATOR"); // default permission for dms - console.log("event", document); - var channel_id = document.channel_id || document.data?.channel_id; - // TODO: clean up - if (document.event === "GUILD_CREATE") { - guilds.push(document.data.id); - eventStream.changeStream(getPipeline.call(this, guilds)); - } else if (document.event === "GUILD_DELETE") { - guilds.remove(document.guild_id!); - eventStream.changeStream(getPipeline.call(this, guilds)); - } else if (document.event === "CHANNEL_DELETE") channel_id = null; - if (document.guild_id && !this.intents.has("GUILDS")) return; - - try { - permission = await getPermission(this.user_id, document.guild_id, channel_id); - } catch (e) { - permission = new Permissions(); - } - - // check intents: https://discord.com/developers/docs/topics/gateway#gateway-intents - switch (document.event) { - case "GUILD_DELETE": - case "GUILD_CREATE": - case "GUILD_UPDATE": - case "GUILD_ROLE_CREATE": - case "GUILD_ROLE_UPDATE": - case "GUILD_ROLE_DELETE": - case "CHANNEL_CREATE": - case "CHANNEL_DELETE": - case "CHANNEL_UPDATE": - // gets sent if GUILDS intent is set (already checked in if document.guild_id) - break; - case "GUILD_INTEGRATIONS_UPDATE": - if (!this.intents.has("GUILD_INTEGRATIONS")) return; - break; - case "WEBHOOKS_UPDATE": - if (!this.intents.has("GUILD_WEBHOOKS")) return; - break; - case "GUILD_EMOJI_UPDATE": - if (!this.intents.has("GUILD_EMOJIS")) return; - break; - // only send them, if the user subscribed for this part of the member list, or is a bot - case "GUILD_MEMBER_ADD": - case "GUILD_MEMBER_REMOVE": - case "GUILD_MEMBER_UPDATE": - if (!this.intents.has("GUILD_MEMBERS")) return; - break; - case "VOICE_STATE_UPDATE": - if (!this.intents.has("GUILD_VOICE_STATES")) return; - break; - case "GUILD_BAN_ADD": - case "GUILD_BAN_REMOVE": - if (!this.intents.has("GUILD_BANS")) return; - break; - case "INVITE_CREATE": - case "INVITE_DELETE": - if (!this.intents.has("GUILD_INVITES")) return; - case "PRESENCE_UPDATE": - if (!this.intents.has("GUILD_PRESENCES")) return; - break; - case "MESSAGE_CREATE": - case "MESSAGE_DELETE": - case "MESSAGE_DELETE_BULK": - case "MESSAGE_UPDATE": - case "CHANNEL_PINS_UPDATE": - if (!this.intents.has("GUILD_MESSAGES") && document.guild_id) return; - if (!this.intents.has("DIRECT_MESSAGES") && !document.guild_id) return; - break; - case "MESSAGE_REACTION_ADD": - case "MESSAGE_REACTION_REMOVE": - case "MESSAGE_REACTION_REMOVE_ALL": - case "MESSAGE_REACTION_REMOVE_EMOJI": - if (!this.intents.has("GUILD_MESSAGE_REACTIONS") && document.guild_id) return; - if (!this.intents.has("DIRECT_MESSAGE_REACTIONS") && !document.guild_id) return; - break; - - case "TYPING_START": - if (!this.intents.has("GUILD_MESSAGE_TYPING") && document.guild_id) return; - if (!this.intents.has("DIRECT_MESSAGE_TYPING") && !document.guild_id) return; - break; - case "READY": // will be sent by the gateway - case "USER_UPDATE": - case "APPLICATION_COMMAND_CREATE": - case "APPLICATION_COMMAND_DELETE": - case "APPLICATION_COMMAND_UPDATE": - default: - // Any events not defined in an intent are considered "passthrough" and will always be sent to you. - break; - } - - // check permissions - switch (document.event) { - case "GUILD_INTEGRATIONS_UPDATE": - if (!permission.has("MANAGE_GUILD")) return; - break; - case "WEBHOOKS_UPDATE": - if (!permission.has("MANAGE_WEBHOOKS")) return; - break; - case "GUILD_MEMBER_ADD": - case "GUILD_MEMBER_REMOVE": - case "GUILD_MEMBER_UPDATE": - // only send them, if the user subscribed for this part of the member list, or is a bot - break; - case "GUILD_BAN_ADD": - case "GUILD_BAN_REMOVE": - if (!permission.has("BAN_MEMBERS")) break; - break; - case "INVITE_CREATE": - case "INVITE_DELETE": - if (!permission.has("MANAGE_GUILD")) break; - case "PRESENCE_UPDATE": - break; - case "VOICE_STATE_UPDATE": - case "MESSAGE_CREATE": - case "MESSAGE_DELETE": - case "MESSAGE_DELETE_BULK": - case "MESSAGE_UPDATE": - case "CHANNEL_PINS_UPDATE": - case "MESSAGE_REACTION_ADD": - case "MESSAGE_REACTION_REMOVE": - case "MESSAGE_REACTION_REMOVE_ALL": - case "MESSAGE_REACTION_REMOVE_EMOJI": - case "TYPING_START": - // only gets send if the user is alowed to view the current channel - if (!permission.has("VIEW_CHANNEL")) return; - break; - case "GUILD_CREATE": - case "GUILD_DELETE": - case "GUILD_UPDATE": - case "GUILD_ROLE_CREATE": - case "GUILD_ROLE_UPDATE": - case "GUILD_ROLE_DELETE": - case "CHANNEL_CREATE": - case "CHANNEL_DELETE": - case "CHANNEL_UPDATE": - case "GUILD_EMOJI_UPDATE": - case "READY": // will be sent by the gateway - case "USER_UPDATE": - case "APPLICATION_COMMAND_CREATE": - case "APPLICATION_COMMAND_DELETE": - case "APPLICATION_COMMAND_UPDATE": - default: - // always gets sent - // Any events not defined in an intent are considered "passthrough" and will always be sent - break; - } - - return Send(this, { - op: OPCODES.Dispatch, - t: document.event, - d: document.data, - s: this.sequence++, - }); + opts.acknowledge?.(); } diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts index 43368367..91f7f675 100644 --- a/gateway/src/opcodes/Identify.ts +++ b/gateway/src/opcodes/Identify.ts @@ -12,7 +12,7 @@ import { toObject, EVENTEnum, Config, -} from "@fosscord/server-util"; +} from "@fosscord/util"; import { setupListener } from "../listener/listener"; import { IdentifySchema } from "../schema/Identify"; import { Send } from "../util/Send"; diff --git a/gateway/src/opcodes/LazyRequest.ts b/gateway/src/opcodes/LazyRequest.ts index b1d553b9..63075e5a 100644 --- a/gateway/src/opcodes/LazyRequest.ts +++ b/gateway/src/opcodes/LazyRequest.ts @@ -1,13 +1,5 @@ // @ts-nocheck WIP -import { - db, - getPermission, - MemberModel, - MongooseCache, - PublicUserProjection, - RoleModel, - toObject, -} from "@fosscord/server-util"; +import { db, getPermission, PublicUserProjection, toObject } from "@fosscord/util"; import { LazyRequest } from "../schema/LazyRequest"; import { OPCODES, Payload } from "../util/Constants"; import { Send } from "../util/Send"; diff --git a/gateway/src/schema/Activity.ts b/gateway/src/schema/Activity.ts index 62cf7ad6..d7e0a30b 100644 --- a/gateway/src/schema/Activity.ts +++ b/gateway/src/schema/Activity.ts @@ -1,4 +1,4 @@ -import { ActivityBodySchema } from "@fosscord/server-util"; +import { ActivityBodySchema } from "@fosscord/util"; import { EmojiSchema } from "./Emoji"; export const ActivitySchema = { diff --git a/gateway/src/util/Config.ts b/gateway/src/util/Config.ts index 9ceb8cd5..e99c89f7 100644 --- a/gateway/src/util/Config.ts +++ b/gateway/src/util/Config.ts @@ -1,6 +1,6 @@ // @ts-nocheck -import { Config } from "@fosscord/server-util"; -import { getConfigPathForFile } from "@fosscord/server-util/dist/util/Config"; +import { Config } from "@fosscord/util"; +import { getConfigPathForFile } from "@fosscord/util/dist/util/Config"; import Ajv, { JSONSchemaType } from "ajv"; export interface DefaultOptions { diff --git a/gateway/src/util/WebSocket.ts b/gateway/src/util/WebSocket.ts index 1bd0ff2f..d1e13555 100644 --- a/gateway/src/util/WebSocket.ts +++ b/gateway/src/util/WebSocket.ts @@ -1,4 +1,4 @@ -import { Intents, Permissions } from "@fosscord/server-util"; +import { Intents, Permissions } from "@fosscord/util"; import WS, { Server, Data } from "ws"; import { Deflate } from "zlib"; import { Channel } from "amqplib"; @@ -15,8 +15,8 @@ interface WebSocket extends WS { readyTimeout: NodeJS.Timeout; intents: Intents; sequence: number; - rabbitCh?: Channel & { queues: Record }; permissions: Record; + events: Record; } export default WebSocket; diff --git a/rtc/package-lock.json b/rtc/package-lock.json deleted file mode 100644 index 4977468d..00000000 Binary files a/rtc/package-lock.json and /dev/null differ diff --git a/rtc/package.json b/rtc/package.json deleted file mode 100644 index 0478fe69..00000000 --- a/rtc/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "@fosscord/server-util", - "version": "1.3.52", - "description": "Utility functions for the all server repositories", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "build": "tsc -b .", - "prepublish": "npm run build" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/fosscord/fosscord-server-util.git" - }, - "keywords": [ - "discord", - "fosscord", - "fosscord-server-util", - "discord open source", - "discord-open-source" - ], - "author": "Fosscord", - "license": "GPLV3", - "bugs": { - "url": "https://github.com/fosscord/fosscord-server-util/issues" - }, - "homepage": "https://docs.fosscord.com/", - "dependencies": { - "@types/jsonwebtoken": "^8.5.0", - "@types/mongoose-autopopulate": "^0.10.1", - "@types/mongoose-lean-virtuals": "^0.5.1", - "@types/node": "^14.14.25", - "ajv": "^8.5.0", - "amqplib": "^0.8.0", - "dot-prop": "^6.0.1", - "env-paths": "^2.2.1", - "jsonwebtoken": "^8.5.1", - "missing-native-js-functions": "^1.2.2", - "mongodb": "^3.6.9", - "mongoose": "^5.12.3", - "mongoose-autopopulate": "^0.12.3", - "typescript": "^4.1.3" - }, - "devDependencies": { - "@types/amqplib": "^0.8.1" - } -} diff --git a/rtc/src/index.ts b/rtc/src/index.ts deleted file mode 100644 index 3565fb6b..00000000 --- a/rtc/src/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export * from "./util/checkToken"; - -export * as Constants from "./util/Constants"; -export * from "./models/index"; -export * from "./util/index"; - -import Config from "./util/Config"; -import db, { MongooseCache, toObject } from "./util/Database"; - -export { Config, db, MongooseCache, toObject }; diff --git a/rtc/src/models/Activity.ts b/rtc/src/models/Activity.ts deleted file mode 100644 index 17abd1ca..00000000 --- a/rtc/src/models/Activity.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { User } from ".."; -import { ClientStatus, Status } from "./Status"; -import { Schema, model, Types, Document } from "mongoose"; -import toBigInt from "../util/toBigInt"; - -export interface Presence { - user: User; - guild_id?: string; - status: Status; - activities: Activity[]; - client_status: ClientStatus; -} - -export interface Activity { - name: string; - type: ActivityType; - url?: string; - created_at?: Date; - timestamps?: { - start?: number; - end?: number; - }[]; - application_id?: string; - details?: string; - state?: string; - emoji?: { - name: string; - id?: string; - amimated?: boolean; - }; - party?: { - id?: string; - size?: [number, number]; - }; - assets?: { - large_image?: string; - large_text?: string; - small_image?: string; - small_text?: string; - }; - secrets?: { - join?: string; - spectate?: string; - match?: string; - }; - instance?: boolean; - flags?: bigint; -} - -export const ActivitySchema = { - name: { type: String, required: true }, - type: { type: Number, required: true }, - url: String, - created_at: Date, - timestamps: [ - { - start: Number, - end: Number, - }, - ], - application_id: String, - details: String, - state: String, - emoji: { - name: String, - id: String, - amimated: Boolean, - }, - party: { - id: String, - size: [Number, Number], - }, - assets: { - large_image: String, - large_text: String, - small_image: String, - small_text: String, - }, - secrets: { - join: String, - spectate: String, - match: String, - }, - instance: Boolean, - flags: { type: String, get: toBigInt }, -}; - -export const ActivityBodySchema = { - name: String, - type: Number, - $url: String, - $created_at: Date, - $timestamps: [ - { - $start: Number, - $end: Number, - }, - ], - $application_id: String, - $details: String, - $state: String, - $emoji: { - $name: String, - $id: String, - $amimated: Boolean, - }, - $party: { - $id: String, - $size: [Number, Number], - }, - $assets: { - $large_image: String, - $large_text: String, - $small_image: String, - $small_text: String, - }, - $secrets: { - $join: String, - $spectate: String, - $match: String, - }, - $instance: Boolean, - $flags: BigInt, -}; - -export enum ActivityType { - GAME = 0, - STREAMING = 1, - LISTENING = 2, - CUSTOM = 4, - COMPETING = 5, -} diff --git a/rtc/src/models/Application.ts b/rtc/src/models/Application.ts deleted file mode 100644 index fae6e8db..00000000 --- a/rtc/src/models/Application.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Team } from "./Team"; - -export interface Application { - id: string; - name: string; - icon: string | null; - description: string; - rpc_origins: string[] | null; - bot_public: boolean; - bot_require_code_grant: boolean; - terms_of_service_url: string | null; - privacy_policy_url: string | null; - owner_id: string; - summary: string | null; - verify_key: string; - team: Team | null; - guild_id: string; // if this application is a game sold on Discord, this field will be the guild to which it has been linked - primary_sku_id: string | null; // if this application is a game sold on Discord, this field will be the id of the "Game SKU" that is created, if exists - slug: string | null; // if this application is a game sold on Discord, this field will be the URL slug that links to the store page - cover_image: string | null; // the application's default rich presence invite cover image hash - flags: number; // the application's public flags -} - -export interface ApplicationCommand { - id: string; - application_id: string; - name: string; - description: string; - options?: ApplicationCommandOption[]; -} - -export interface ApplicationCommandOption { - type: ApplicationCommandOptionType; - name: string; - description: string; - required?: boolean; - choices?: ApplicationCommandOptionChoice[]; - options?: ApplicationCommandOption[]; -} - -export interface ApplicationCommandOptionChoice { - name: string; - value: string | number; -} - -export enum ApplicationCommandOptionType { - SUB_COMMAND = 1, - SUB_COMMAND_GROUP = 2, - STRING = 3, - INTEGER = 4, - BOOLEAN = 5, - USER = 6, - CHANNEL = 7, - ROLE = 8, -} - -export interface ApplicationCommandInteractionData { - id: string; - name: string; - options?: ApplicationCommandInteractionDataOption[]; -} - -export interface ApplicationCommandInteractionDataOption { - name: string; - value?: any; - options?: ApplicationCommandInteractionDataOption[]; -} diff --git a/rtc/src/models/AuditLog.ts b/rtc/src/models/AuditLog.ts deleted file mode 100644 index 02b2c444..00000000 --- a/rtc/src/models/AuditLog.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { Schema, Document, Types } from "mongoose"; -import db from "../util/Database"; -import { ChannelPermissionOverwrite } from "./Channel"; -import { PublicUser } from "./User"; - -export interface AuditLogResponse { - webhooks: []; // TODO: - users: PublicUser[]; - audit_log_entries: AuditLogEntries[]; - integrations: []; // TODO: -} - -export interface AuditLogEntries { - target_id?: string; - user_id: string; - id: string; - action_type: AuditLogEvents; - options?: { - delete_member_days?: string; - members_removed?: string; - channel_id?: string; - messaged_id?: string; - count?: string; - id?: string; - type?: string; - role_name?: string; - }; - changes: AuditLogChange[]; - reason?: string; -} - -export interface AuditLogChange { - new_value?: AuditLogChangeValue; - old_value?: AuditLogChangeValue; - key: string; -} - -export interface AuditLogChangeValue { - name?: string; - description?: string; - icon_hash?: string; - splash_hash?: string; - discovery_splash_hash?: string; - banner_hash?: string; - owner_id?: string; - region?: string; - preferred_locale?: string; - afk_channel_id?: string; - afk_timeout?: number; - rules_channel_id?: string; - public_updates_channel_id?: string; - mfa_level?: number; - verification_level?: number; - explicit_content_filter?: number; - default_message_notifications?: number; - vanity_url_code?: string; - $add?: {}[]; - $remove?: {}[]; - prune_delete_days?: number; - widget_enabled?: boolean; - widget_channel_id?: string; - system_channel_id?: string; - position?: number; - topic?: string; - bitrate?: number; - permission_overwrites?: ChannelPermissionOverwrite[]; - nsfw?: boolean; - application_id?: string; - rate_limit_per_user?: number; - permissions?: string; - color?: number; - hoist?: boolean; - mentionable?: boolean; - allow?: string; - deny?: string; - code?: string; - channel_id?: string; - inviter_id?: string; - max_uses?: number; - uses?: number; - max_age?: number; - temporary?: boolean; - deaf?: boolean; - mute?: boolean; - nick?: string; - avatar_hash?: string; - id?: string; - type?: number; - enable_emoticons?: boolean; - expire_behavior?: number; - expire_grace_period?: number; - user_limit?: number; -} - -export interface AuditLogEntriesDocument extends Document, AuditLogEntries { - id: string; -} - -export const AuditLogChanges = { - name: String, - description: String, - icon_hash: String, - splash_hash: String, - discovery_splash_hash: String, - banner_hash: String, - owner_id: String, - region: String, - preferred_locale: String, - afk_channel_id: String, - afk_timeout: Number, - rules_channel_id: String, - public_updates_channel_id: String, - mfa_level: Number, - verification_level: Number, - explicit_content_filter: Number, - default_message_notifications: Number, - vanity_url_code: String, - $add: [{}], - $remove: [{}], - prune_delete_days: Number, - widget_enabled: Boolean, - widget_channel_id: String, - system_channel_id: String, - position: Number, - topic: String, - bitrate: Number, - permission_overwrites: [{}], - nsfw: Boolean, - application_id: String, - rate_limit_per_user: Number, - permissions: String, - color: Number, - hoist: Boolean, - mentionable: Boolean, - allow: String, - deny: String, - code: String, - channel_id: String, - inviter_id: String, - max_uses: Number, - uses: Number, - max_age: Number, - temporary: Boolean, - deaf: Boolean, - mute: Boolean, - nick: String, - avatar_hash: String, - id: String, - type: Number, - enable_emoticons: Boolean, - expire_behavior: Number, - expire_grace_period: Number, - user_limit: Number, -}; - -export const AuditLogSchema = new Schema({ - target_id: String, - user_id: { type: String, required: true }, - id: { type: String, required: true }, - action_type: { type: Number, required: true }, - options: { - delete_member_days: String, - members_removed: String, - channel_id: String, - messaged_id: String, - count: String, - id: String, - type: { type: Number }, - role_name: String, - }, - changes: [ - { - new_value: AuditLogChanges, - old_value: AuditLogChanges, - key: String, - }, - ], - reason: String, -}); - -// @ts-ignore -export const AuditLogModel = db.model("AuditLog", AuditLogSchema, "auditlogs"); - -export enum AuditLogEvents { - GUILD_UPDATE = 1, - CHANNEL_CREATE = 10, - CHANNEL_UPDATE = 11, - CHANNEL_DELETE = 12, - CHANNEL_OVERWRITE_CREATE = 13, - CHANNEL_OVERWRITE_UPDATE = 14, - CHANNEL_OVERWRITE_DELETE = 15, - MEMBER_KICK = 20, - MEMBER_PRUNE = 21, - MEMBER_BAN_ADD = 22, - MEMBER_BAN_REMOVE = 23, - MEMBER_UPDATE = 24, - MEMBER_ROLE_UPDATE = 25, - MEMBER_MOVE = 26, - MEMBER_DISCONNECT = 27, - BOT_ADD = 28, - ROLE_CREATE = 30, - ROLE_UPDATE = 31, - ROLE_DELETE = 32, - INVITE_CREATE = 40, - INVITE_UPDATE = 41, - INVITE_DELETE = 42, - WEBHOOK_CREATE = 50, - WEBHOOK_UPDATE = 51, - WEBHOOK_DELETE = 52, - EMOJI_CREATE = 60, - EMOJI_UPDATE = 61, - EMOJI_DELETE = 62, - MESSAGE_DELETE = 72, - MESSAGE_BULK_DELETE = 73, - MESSAGE_PIN = 74, - MESSAGE_UNPIN = 75, - INTEGRATION_CREATE = 80, - INTEGRATION_UPDATE = 81, - INTEGRATION_DELETE = 82, -} diff --git a/rtc/src/models/Ban.ts b/rtc/src/models/Ban.ts deleted file mode 100644 index f09950ee..00000000 --- a/rtc/src/models/Ban.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Schema, model, Types, Document } from "mongoose"; -import db from "../util/Database"; -import { PublicUserProjection, UserModel } from "./User"; - -export interface Ban extends Document { - user_id: string; - guild_id: string; - executor_id: string; - ip: string; - reason?: string; -} - -export const BanSchema = new Schema({ - user_id: { type: String, required: true }, - guild_id: { type: String, required: true }, - executor_id: { type: String, required: true }, - reason: String, - ip: String, // ? Should we store this in here, or in the UserModel? -}); - -BanSchema.virtual("user", { - ref: UserModel, - localField: "user_id", - foreignField: "id", - justOne: true, - autopopulate: { select: PublicUserProjection }, -}); - -BanSchema.set("removeResponse", ["user_id"]); - -// @ts-ignore -export const BanModel = db.model("Ban", BanSchema, "bans"); diff --git a/rtc/src/models/Channel.ts b/rtc/src/models/Channel.ts deleted file mode 100644 index 1dd05896..00000000 --- a/rtc/src/models/Channel.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { Schema, model, Types, Document } from "mongoose"; -import db from "../util/Database"; -import toBigInt from "../util/toBigInt"; -import { PublicUserProjection, UserModel } from "./User"; - -// @ts-ignore -export interface AnyChannel extends Channel, DMChannel, TextChannel, VoiceChannel { - recipient_ids: null | string[]; -} - -export interface ChannelDocument extends Document, AnyChannel { - id: string; -} - -export const ChannelSchema = new Schema({ - id: String, - created_at: { type: Schema.Types.Date, required: true }, - name: String, // can't be required for dm channels - type: { type: Number, required: true }, - guild_id: String, - owner_id: String, - parent_id: String, - recipient_ids: [String], - position: Number, - last_message_id: String, - last_pin_timestamp: Date, - nsfw: Boolean, - rate_limit_per_user: Number, - topic: String, - permission_overwrites: [ - { - allow: { type: String, get: toBigInt }, - deny: { type: String, get: toBigInt }, - id: String, - type: { type: Number }, - }, - ], -}); - -ChannelSchema.virtual("recipients", { - ref: UserModel, - localField: "recipient_ids", - foreignField: "id", - justOne: false, - autopopulate: { select: PublicUserProjection }, -}); - -ChannelSchema.set("removeResponse", ["recipient_ids"]); - -// @ts-ignore -export const ChannelModel = db.model("Channel", ChannelSchema, "channels"); - -export interface Channel { - id: string; - created_at: Date; - name: string; - type: number; -} - -export interface TextBasedChannel { - last_message_id?: string; - last_pin_timestamp?: number; -} - -export interface GuildChannel extends Channel { - guild_id: string; - position: number; - parent_id?: string; - permission_overwrites: ChannelPermissionOverwrite[]; -} - -export interface ChannelPermissionOverwrite { - allow: bigint; // for bitfields we use bigints - deny: bigint; // for bitfields we use bigints - id: string; - type: ChannelPermissionOverwriteType; -} - -export enum ChannelPermissionOverwriteType { - role = 0, - member = 1, -} - -export interface VoiceChannel extends GuildChannel { - video_quality_mode?: number; - bitrate?: number; - user_limit?: number; -} - -export interface TextChannel extends GuildChannel, TextBasedChannel { - nsfw: boolean; - rate_limit_per_user: number; - topic?: string; -} -// @ts-ignore -export interface DMChannel extends Channel, TextBasedChannel { - owner_id: string; - recipient_ids: string[]; -} - -export enum ChannelType { - GUILD_TEXT = 0, // a text channel within a server - DM = 1, // a direct message between users - GUILD_VOICE = 2, // a voice channel within a server - GROUP_DM = 3, // a direct message between multiple users - GUILD_CATEGORY = 4, // an organizational category that contains up to 50 channels - GUILD_NEWS = 5, // a channel that users can follow and crosspost into their own server - GUILD_STORE = 6, // a channel in which game developers can sell their game on Discord -} diff --git a/rtc/src/models/Emoji.ts b/rtc/src/models/Emoji.ts deleted file mode 100644 index 3e5cad53..00000000 --- a/rtc/src/models/Emoji.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Schema, model, Types, Document } from "mongoose"; -import db from "../util/Database"; - -export interface Emoji extends Document { - id: string; - animated: boolean; - available: boolean; - guild_id: string; - managed: boolean; - name: string; - require_colons: boolean; - url: string; - roles: string[]; // roles this emoji is whitelisted to (new discord feature?) -} - -export const EmojiSchema = new Schema({ - id: { type: String, required: true }, - animated: Boolean, - available: Boolean, - guild_id: String, - managed: Boolean, - name: String, - require_colons: Boolean, - url: String, - roles: [String], -}); - -// @ts-ignore -export const EmojiModel = db.model("Emoji", EmojiSchema, "emojis"); diff --git a/rtc/src/models/Event.ts b/rtc/src/models/Event.ts deleted file mode 100644 index 1564107d..00000000 --- a/rtc/src/models/Event.ts +++ /dev/null @@ -1,540 +0,0 @@ -import { ConnectedAccount, PublicUser, Relationship, User, UserSettings } from "./User"; -import { DMChannel, Channel } from "./Channel"; -import { Guild } from "./Guild"; -import { Member, PublicMember, UserGuildSettings } from "./Member"; -import { Emoji } from "./Emoji"; -import { Presence } from "./Activity"; -import { Role } from "./Role"; -import { Invite } from "./Invite"; -import { Message, PartialEmoji } from "./Message"; -import { VoiceState } from "./VoiceState"; -import { ApplicationCommand } from "./Application"; -import { Interaction } from "./Interaction"; -import { Schema, model, Types, Document } from "mongoose"; -import db from "../util/Database"; - -export interface Event { - guild_id?: string; - user_id?: string; - channel_id?: string; - created_at?: Date; - event: EVENT; - data?: any; -} - -export interface EventDocument extends Event, Document {} - -export const EventSchema = new Schema({ - guild_id: String, - user_id: String, - channel_id: String, - created_at: { type: Date, required: true }, - event: { type: String, required: true }, - data: Object, -}); - -// @ts-ignore -export const EventModel = db.model("Event", EventSchema, "events"); - -// ! Custom Events that shouldn't get sent to the client but processed by the server - -export interface InvalidatedEvent extends Event { - event: "INVALIDATED"; -} - -// ! END Custom Events that shouldn't get sent to the client but processed by the server - -export interface ReadyEventData { - v: number; - user: PublicUser & { - mobile: boolean; - desktop: boolean; - email: string | null; - flags: bigint; - mfa_enabled: boolean; - nsfw_allowed: boolean; - phone: string | null; - premium: boolean; - premium_type: number; - verified: boolean; - bot: boolean; - }; - private_channels: DMChannel[]; // this will be empty for bots - session_id: string; // resuming - guilds: Guild[]; - analytics_token?: string; - connected_accounts?: ConnectedAccount[]; - consents?: { - personalization?: { - consented?: boolean; - }; - }; - country_code?: string; // e.g. DE - friend_suggestion_count?: number; - geo_ordered_rtc_regions?: string[]; // ["europe","russie","india","us-east","us-central"] - experiments?: [number, number, number, number, number][]; - guild_experiments?: [ - // ? what are guild_experiments? - // this is the structure of it: - number, - null, - number, - [[number, { e: number; s: number }[]]], - [number, [[number, [number, number]]]], - { b: number; k: bigint[] }[] - ][]; - guild_join_requests?: []; // ? what is this? this is new - shard?: [number, number]; - user_settings?: UserSettings; - relationships?: Relationship[]; // TODO - read_state: { - entries: []; // TODO - partial: boolean; - version: number; - }; - user_guild_settings?: { - entries: UserGuildSettings[]; - version: number; - partial: boolean; - }; - application?: { - id: string; - flags: bigint; - }; - merged_members?: Omit[][]; - // probably all users who the user is in contact with - users?: { - avatar: string | null; - discriminator: string; - id: string; - username: string; - bot: boolean; - public_flags: bigint; - }[]; -} - -export interface ReadyEvent extends Event { - event: "READY"; - data: ReadyEventData; -} - -export interface ChannelCreateEvent extends Event { - event: "CHANNEL_CREATE"; - data: Channel; -} - -export interface ChannelUpdateEvent extends Event { - event: "CHANNEL_UPDATE"; - data: Channel; -} - -export interface ChannelDeleteEvent extends Event { - event: "CHANNEL_DELETE"; - data: Channel; -} - -export interface ChannelPinsUpdateEvent extends Event { - event: "CHANNEL_PINS_UPDATE"; - data: { - guild_id?: string; - channel_id: string; - last_pin_timestamp?: number; - }; -} - -export interface GuildCreateEvent extends Event { - event: "GUILD_CREATE"; - data: Guild; -} - -export interface GuildUpdateEvent extends Event { - event: "GUILD_UPDATE"; - data: Guild; -} - -export interface GuildDeleteEvent extends Event { - event: "GUILD_DELETE"; - data: { - id: string; - unavailable?: boolean; - }; -} - -export interface GuildBanAddEvent extends Event { - event: "GUILD_BAN_ADD"; - data: { - guild_id: string; - user: User; - }; -} - -export interface GuildBanRemoveEvent extends Event { - event: "GUILD_BAN_REMOVE"; - data: { - guild_id: string; - user: User; - }; -} - -export interface GuildEmojiUpdateEvent extends Event { - event: "GUILD_EMOJI_UPDATE"; - data: { - guild_id: string; - emojis: Emoji[]; - }; -} - -export interface GuildIntegrationUpdateEvent extends Event { - event: "GUILD_INTEGRATIONS_UPDATE"; - data: { - guild_id: string; - }; -} - -export interface GuildMemberAddEvent extends Event { - event: "GUILD_MEMBER_ADD"; - data: PublicMember & { - guild_id: string; - }; -} - -export interface GuildMemberRemoveEvent extends Event { - event: "GUILD_MEMBER_REMOVE"; - data: { - guild_id: string; - user: User; - }; -} - -export interface GuildMemberUpdateEvent extends Event { - event: "GUILD_MEMBER_UPDATE"; - data: { - guild_id: string; - roles: string[]; - user: User; - nick?: string; - joined_at?: Date; - premium_since?: number; - pending?: boolean; - }; -} - -export interface GuildMembersChunkEvent extends Event { - event: "GUILD_MEMBERS_CHUNK"; - data: { - guild_id: string; - members: PublicMember[]; - chunk_index: number; - chunk_count: number; - not_found: string[]; - presences: Presence[]; - nonce?: string; - }; -} - -export interface GuildRoleCreateEvent extends Event { - event: "GUILD_ROLE_CREATE"; - data: { - guild_id: string; - role: Role; - }; -} - -export interface GuildRoleUpdateEvent extends Event { - event: "GUILD_ROLE_UPDATE"; - data: { - guild_id: string; - role: Role; - }; -} - -export interface GuildRoleDeleteEvent extends Event { - event: "GUILD_ROLE_DELETE"; - data: { - guild_id: string; - role_id: string; - }; -} - -export interface InviteCreateEvent extends Event { - event: "INVITE_CREATE"; - data: Omit & { - channel_id: string; - guild_id?: string; - }; -} - -export interface InviteDeleteEvent extends Event { - event: "INVITE_DELETE"; - data: { - channel_id: string; - guild_id?: string; - code: string; - }; -} - -export type MessagePayload = Omit & { - channel_id: string; - guild_id?: string; - author: PublicUser; - member: PublicMember; - mentions: (PublicUser & { member: PublicMember })[]; -}; - -export interface MessageCreateEvent extends Event { - event: "MESSAGE_CREATE"; - data: MessagePayload; -} - -export interface MessageUpdateEvent extends Event { - event: "MESSAGE_UPDATE"; - data: MessagePayload; -} - -export interface MessageDeleteEvent extends Event { - event: "MESSAGE_DELETE"; - data: { - id: string; - channel_id: string; - guild_id?: string; - }; -} - -export interface MessageDeleteBulkEvent extends Event { - event: "MESSAGE_DELETE_BULK"; - data: { - ids: string[]; - channel_id: string; - guild_id?: string; - }; -} - -export interface MessageReactionAddEvent extends Event { - event: "MESSAGE_REACTION_ADD"; - data: { - user_id: string; - channel_id: string; - message_id: string; - guild_id?: string; - member?: PublicMember; - emoji: PartialEmoji; - }; -} - -export interface MessageReactionRemoveEvent extends Event { - event: "MESSAGE_REACTION_REMOVE"; - data: { - user_id: string; - channel_id: string; - message_id: string; - guild_id?: string; - emoji: PartialEmoji; - }; -} - -export interface MessageReactionRemoveAllEvent extends Event { - event: "MESSAGE_REACTION_REMOVE_ALL"; - data: { - channel_id: string; - message_id: string; - guild_id?: string; - }; -} - -export interface MessageReactionRemoveEmojiEvent extends Event { - event: "MESSAGE_REACTION_REMOVE_EMOJI"; - data: { - channel_id: string; - message_id: string; - guild_id?: string; - emoji: PartialEmoji; - }; -} - -export interface PresenceUpdateEvent extends Event { - event: "PRESENCE_UPDATE"; - data: Presence; -} - -export interface TypingStartEvent extends Event { - event: "TYPING_START"; - data: { - channel_id: string; - user_id: string; - timestamp: number; - guild_id?: string; - member?: PublicMember; - }; -} - -export interface UserUpdateEvent extends Event { - event: "USER_UPDATE"; - data: User; -} - -export interface VoiceStateUpdateEvent extends Event { - event: "VOICE_STATE_UPDATE"; - data: VoiceState & { - member: PublicMember; - }; -} - -export interface VoiceServerUpdateEvent extends Event { - event: "VOICE_SERVER_UPDATE"; - data: { - token: string; - guild_id: string; - endpoint: string; - }; -} - -export interface WebhooksUpdateEvent extends Event { - event: "WEBHOOKS_UPDATE"; - data: { - guild_id: string; - channel_id: string; - }; -} - -export type ApplicationCommandPayload = ApplicationCommand & { - guild_id: string; -}; - -export interface ApplicationCommandCreateEvent extends Event { - event: "APPLICATION_COMMAND_CREATE"; - data: ApplicationCommandPayload; -} - -export interface ApplicationCommandUpdateEvent extends Event { - event: "APPLICATION_COMMAND_UPDATE"; - data: ApplicationCommandPayload; -} - -export interface ApplicationCommandDeleteEvent extends Event { - event: "APPLICATION_COMMAND_DELETE"; - data: ApplicationCommandPayload; -} - -export interface InteractionCreateEvent extends Event { - event: "INTERACTION_CREATE"; - data: Interaction; -} - -export interface MessageAckEvent extends Event { - event: "MESSAGE_ACK"; - data: { - channel_id: string; - message_id: string; - version?: number; - manual?: boolean; - mention_count?: number; - }; -} - -export interface RelationshipAddEvent extends Event { - event: "RELATIONSHIP_ADD"; - data: Relationship & { - should_notify?: boolean; - user: PublicUser; - }; -} - -export interface RelationshipRemoveEvent extends Event { - event: "RELATIONSHIP_REMOVE"; - data: Omit; -} - -// located in collection events - -export enum EVENTEnum { - Ready = "READY", - ChannelCreate = "CHANNEL_CREATE", - ChannelUpdate = "CHANNEL_UPDATE", - ChannelDelete = "CHANNEL_DELETE", - ChannelPinsUpdate = "CHANNEL_PINS_UPDATE", - GuildCreate = "GUILD_CREATE", - GuildUpdate = "GUILD_UPDATE", - GuildDelete = "GUILD_DELETE", - GuildBanAdd = "GUILD_BAN_ADD", - GuildBanRemove = "GUILD_BAN_REMOVE", - GuildEmojUpdate = "GUILD_EMOJI_UPDATE", - GuildIntegrationsUpdate = "GUILD_INTEGRATIONS_UPDATE", - GuildMemberAdd = "GUILD_MEMBER_ADD", - GuildMemberRempve = "GUILD_MEMBER_REMOVE", - GuildMemberUpdate = "GUILD_MEMBER_UPDATE", - GuildMemberSpeaking = "GUILD_MEMBER_SPEAKING", - GuildMembersChunk = "GUILD_MEMBERS_CHUNK", - GuildRoleCreate = "GUILD_ROLE_CREATE", - GuildRoleDelete = "GUILD_ROLE_DELETE", - GuildRoleUpdate = "GUILD_ROLE_UPDATE", - InviteCreate = "INVITE_CREATE", - InviteDelete = "INVITE_DELETE", - MessageCreate = "MESSAGE_CREATE", - MessageUpdate = "MESSAGE_UPDATE", - MessageDelete = "MESSAGE_DELETE", - MessageDeleteBulk = "MESSAGE_DELETE_BULK", - MessageReactionAdd = "MESSAGE_REACTION_ADD", - MessageReactionRemove = "MESSAGE_REACTION_REMOVE", - MessageReactionRemoveAll = "MESSAGE_REACTION_REMOVE_ALL", - MessageReactionRemoveEmoji = "MESSAGE_REACTION_REMOVE_EMOJI", - PresenceUpdate = "PRESENCE_UPDATE", - TypingStart = "TYPING_START", - UserUpdate = "USER_UPDATE", - WebhooksUpdate = "WEBHOOKS_UPDATE", - InteractionCreate = "INTERACTION_CREATE", - VoiceStateUpdate = "VOICE_STATE_UPDATE", - VoiceServerUpdate = "VOICE_SERVER_UPDATE", - ApplicationCommandCreate = "APPLICATION_COMMAND_CREATE", - ApplicationCommandUpdate = "APPLICATION_COMMAND_UPDATE", - ApplicationCommandDelete = "APPLICATION_COMMAND_DELETE", -} - -export type EVENT = - | "READY" - | "CHANNEL_CREATE" - | "CHANNEL_UPDATE" - | "CHANNEL_DELETE" - | "CHANNEL_PINS_UPDATE" - | "GUILD_CREATE" - | "GUILD_UPDATE" - | "GUILD_DELETE" - | "GUILD_BAN_ADD" - | "GUILD_BAN_REMOVE" - | "GUILD_EMOJI_UPDATE" - | "GUILD_INTEGRATIONS_UPDATE" - | "GUILD_MEMBER_ADD" - | "GUILD_MEMBER_REMOVE" - | "GUILD_MEMBER_UPDATE" - | "GUILD_MEMBER_SPEAKING" - | "GUILD_MEMBERS_CHUNK" - | "GUILD_ROLE_CREATE" - | "GUILD_ROLE_DELETE" - | "GUILD_ROLE_UPDATE" - | "INVITE_CREATE" - | "INVITE_DELETE" - | "MESSAGE_CREATE" - | "MESSAGE_UPDATE" - | "MESSAGE_DELETE" - | "MESSAGE_DELETE_BULK" - | "MESSAGE_REACTION_ADD" - // TODO: add a new event: bulk add reaction: - // | "MESSAGE_REACTION_BULK_ADD" - | "MESSAGE_REACTION_REMOVE" - | "MESSAGE_REACTION_REMOVE_ALL" - | "MESSAGE_REACTION_REMOVE_EMOJI" - | "PRESENCE_UPDATE" - | "TYPING_START" - | "USER_UPDATE" - | "WEBHOOKS_UPDATE" - | "INTERACTION_CREATE" - | "VOICE_STATE_UPDATE" - | "VOICE_SERVER_UPDATE" - | "APPLICATION_COMMAND_CREATE" - | "APPLICATION_COMMAND_UPDATE" - | "APPLICATION_COMMAND_DELETE" - | "MESSAGE_ACK" - | "RELATIONSHIP_ADD" - | "RELATIONSHIP_REMOVE" - | CUSTOMEVENTS; - -export type CUSTOMEVENTS = "INVALIDATED"; diff --git a/rtc/src/models/Guild.ts b/rtc/src/models/Guild.ts deleted file mode 100644 index 13a7d078..00000000 --- a/rtc/src/models/Guild.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { Schema, model, Types, Document } from "mongoose"; -import db from "../util/Database"; -import { ChannelModel } from "./Channel"; -import { EmojiModel } from "./Emoji"; -import { MemberModel } from "./Member"; -import { RoleModel } from "./Role"; - -export interface GuildDocument extends Document, Guild { - id: string; -} - -export interface Guild { - id: string; - afk_channel_id?: string; - afk_timeout?: number; - application_id?: string; - banner?: string; - default_message_notifications?: number; - description?: string; - discovery_splash?: string; - explicit_content_filter?: number; - features: string[]; - icon?: string; - large?: boolean; - max_members?: number; // e.g. default 100.000 - max_presences?: number; - max_video_channel_users?: number; // ? default: 25, is this max 25 streaming or watching - member_count?: number; - presence_count?: number; // users online - // members?: Member[]; // * Members are stored in a seperate collection - // roles: Role[]; // * Role are stored in a seperate collection - // channels: GuildChannel[]; // * Channels are stored in a seperate collection - // emojis: Emoji[]; // * Emojis are stored in a seperate collection - // voice_states: []; // * voice_states are stored in a seperate collection - //TODO: - presences?: object[]; - mfa_level?: number; - name: string; - owner_id: string; - preferred_locale?: string; // only community guilds can choose this - premium_subscription_count?: number; - premium_tier?: number; // nitro boost level - public_updates_channel_id?: string; - region?: string; - rules_channel_id?: string; - splash?: string; - system_channel_flags?: number; - system_channel_id?: string; - unavailable?: boolean; - vanity_url?: { - code: string; - uses: number; - }; - verification_level?: number; - welcome_screen: { - enabled: boolean; - description: string; - welcome_channels: { - description: string; - emoji_id?: string; - emoji_name: string; - channel_id: string }[]; - }; - widget_channel_id?: string; - widget_enabled?: boolean; -} - -export const GuildSchema = new Schema({ - id: { type: String, required: true }, - afk_channel_id: String, - afk_timeout: Number, - application_id: String, - banner: String, - default_message_notifications: Number, - description: String, - discovery_splash: String, - explicit_content_filter: Number, - features: { type: [String], default: [] }, - icon: String, - large: Boolean, - max_members: { type: Number, default: 100000 }, - max_presences: Number, - max_video_channel_users: { type: Number, default: 25 }, - member_count: Number, - presences: { type: [Object], default: [] }, - presence_count: Number, - mfa_level: Number, - name: { type: String, required: true }, - owner_id: { type: String, required: true }, - preferred_locale: String, - premium_subscription_count: Number, - premium_tier: Number, - public_updates_channel_id: String, - region: String, - rules_channel_id: String, - splash: String, - system_channel_flags: Number, - system_channel_id: String, - unavailable: Boolean, - vanity_url: { - code: String, - uses: Number - }, - verification_level: Number, - voice_states: { type: [Object], default: [] }, - welcome_screen: { - enabled: Boolean, - description: String, - welcome_channels: [{ - description: String, - emoji_id: String, - emoji_name: String, - channel_id: String }], - }, - widget_channel_id: String, - widget_enabled: Boolean, -}); - -GuildSchema.virtual("channels", { - ref: ChannelModel, - localField: "id", - foreignField: "guild_id", - justOne: false, - autopopulate: true, -}); - -GuildSchema.virtual("roles", { - ref: RoleModel, - localField: "id", - foreignField: "guild_id", - justOne: false, - autopopulate: true, -}); - -// nested populate is needed for member users: https://gist.github.com/yangsu/5312204 -GuildSchema.virtual("members", { - ref: MemberModel, - localField: "id", - foreignField: "guild_id", - justOne: false, -}); - -GuildSchema.virtual("emojis", { - ref: EmojiModel, - localField: "id", - foreignField: "guild_id", - justOne: false, - autopopulate: true, -}); - -GuildSchema.virtual("joined_at", { - ref: MemberModel, - localField: "id", - foreignField: "guild_id", - justOne: true, -}).get((member: any, virtual: any, doc: any) => { - return member?.joined_at; -}); - -// @ts-ignore -export const GuildModel = db.model("Guild", GuildSchema, "guilds"); diff --git a/rtc/src/models/Interaction.ts b/rtc/src/models/Interaction.ts deleted file mode 100644 index 764247a5..00000000 --- a/rtc/src/models/Interaction.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AllowedMentions, Embed } from "./Message"; - -export interface Interaction { - id: string; - type: InteractionType; - data?: {}; - guild_id: string; - channel_id: string; - member_id: string; - token: string; - version: number; -} - -export enum InteractionType { - Ping = 1, - ApplicationCommand = 2, -} - -export enum InteractionResponseType { - Pong = 1, - Acknowledge = 2, - ChannelMessage = 3, - ChannelMessageWithSource = 4, - AcknowledgeWithSource = 5, -} - -export interface InteractionApplicationCommandCallbackData { - tts?: boolean; - content: string; - embeds?: Embed[]; - allowed_mentions?: AllowedMentions; -} diff --git a/rtc/src/models/Invite.ts b/rtc/src/models/Invite.ts deleted file mode 100644 index 01f12003..00000000 --- a/rtc/src/models/Invite.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Schema, Document, Types } from "mongoose"; -import db from "../util/Database"; -import { ChannelModel } from "./Channel"; -import { PublicUserProjection, UserModel } from "./User"; -import { GuildModel } from "./Guild"; - -export interface Invite { - code: string; - temporary: boolean; - uses: number; - max_uses: number; - max_age: number; - created_at: Date; - expires_at: Date; - guild_id: string; - channel_id: string; - inviter_id: string; - - // ? What is this? - target_user_id?: string; - target_user_type?: number; -} - -export interface InviteDocument extends Invite, Document {} - -export const InviteSchema = new Schema({ - code: String, - temporary: Boolean, - uses: Number, - max_uses: Number, - max_age: Number, - created_at: Date, - expires_at: Date, - guild_id: String, - channel_id: String, - inviter_id: String, - - // ? What is this? - target_user_id: String, - target_user_type: Number, -}); - -InviteSchema.virtual("channel", { - ref: ChannelModel, - localField: "channel_id", - foreignField: "id", - justOne: true, - autopopulate: { - select: { - id: true, - name: true, - type: true, - }, - }, -}); - -InviteSchema.virtual("inviter", { - ref: UserModel, - localField: "inviter_id", - foreignField: "id", - justOne: true, - autopopulate: { - select: PublicUserProjection, - }, -}); - -InviteSchema.virtual("guild", { - ref: GuildModel, - localField: "guild_id", - foreignField: "id", - justOne: true, - autopopulate: { - select: { - id: true, - name: true, - splash: true, - banner: true, - description: true, - icon: true, - features: true, - verification_level: true, - vanity_url_code: true, - welcome_screen: true, - nsfw: true, - - // TODO: hide the following entries: - // channels: false, - // roles: false, - // emojis: false, - }, - }, -}); - -// @ts-ignore -export const InviteModel = db.model("Invite", InviteSchema, "invites"); diff --git a/rtc/src/models/Member.ts b/rtc/src/models/Member.ts deleted file mode 100644 index d1c9ad9b..00000000 --- a/rtc/src/models/Member.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { PublicUser, PublicUserProjection, User, UserModel } from "./User"; -import { Schema, Types, Document } from "mongoose"; -import db from "../util/Database"; - -export const PublicMemberProjection = { - id: true, - guild_id: true, - nick: true, - roles: true, - joined_at: true, - pending: true, - deaf: true, - mute: true, - premium_since: true, -}; - -export interface Member { - id: string; - guild_id: string; - nick?: string; - roles: string[]; - joined_at: Date; - premium_since?: number; - deaf: boolean; - mute: boolean; - pending: boolean; - settings: UserGuildSettings; - read_state: Record; - // virtual - user?: User; -} - -export interface MemberDocument extends Member, Document { - id: string; -} - -export interface UserGuildSettings { - channel_overrides: { - channel_id: string; - message_notifications: number; - mute_config: MuteConfig; - muted: boolean; - }[]; - message_notifications: number; - mobile_push: boolean; - mute_config: MuteConfig; - muted: boolean; - suppress_everyone: boolean; - suppress_roles: boolean; - version: number; -} - -export interface MuteConfig { - end_time: number; - selected_time_window: number; -} - -const MuteConfig = { - end_time: Number, - selected_time_window: Number, -}; - -export const MemberSchema = new Schema({ - id: { type: String, required: true }, - guild_id: String, - nick: String, - roles: [String], - joined_at: Date, - premium_since: Number, - deaf: Boolean, - mute: Boolean, - pending: Boolean, - read_state: Object, - settings: { - channel_overrides: [ - { - channel_id: String, - message_notifications: Number, - mute_config: MuteConfig, - muted: Boolean, - }, - ], - message_notifications: Number, - mobile_push: Boolean, - mute_config: MuteConfig, - muted: Boolean, - suppress_everyone: Boolean, - suppress_roles: Boolean, - version: Number, - }, -}); - -MemberSchema.virtual("user", { - ref: UserModel, - localField: "id", - foreignField: "id", - justOne: true, - autopopulate: { - select: PublicUserProjection, - }, -}); - -// @ts-ignore -export const MemberModel = db.model("Member", MemberSchema, "members"); - -// @ts-ignore -export interface PublicMember extends Omit { - user: PublicUser; -} diff --git a/rtc/src/models/Message.ts b/rtc/src/models/Message.ts deleted file mode 100644 index 15a6f40d..00000000 --- a/rtc/src/models/Message.ts +++ /dev/null @@ -1,368 +0,0 @@ -import { Schema, Types, Document } from "mongoose"; -import db from "../util/Database"; -import { PublicUser, PublicUserProjection, UserModel } from "./User"; -import { MemberModel, PublicMember } from "./Member"; -import { Role, RoleModel } from "./Role"; -import { Channel } from "./Channel"; -import { Snowflake } from "../util"; -import { InteractionType } from "./Interaction"; - -export interface Message { - id: string; - channel_id: string; - guild_id?: string; - author_id?: string; - webhook_id?: string; - application_id?: string; - content?: string; - timestamp: Date; - edited_timestamp: Date | null; - tts?: boolean; - mention_everyone?: boolean; - mention_user_ids: string[]; - mention_role_ids: string[]; - mention_channels_ids: string[]; - attachments: Attachment[]; - embeds: Embed[]; - reactions: Reaction[]; - nonce?: string | number; - pinned?: boolean; - type: MessageType; - activity?: { - type: number; - party_id: string; - }; - flags?: bigint; - stickers?: any[]; - message_reference?: { - message_id: string; - channel_id?: string; - guild_id?: string; - }; - interaction?: { - id: string; - type: InteractionType; - name: string; - user_id: string; // the user who invoked the interaction - // user: User; // TODO: autopopulate user - }; - components: MessageComponent[]; - - // * mongoose virtuals: - // TODO: - // application: Application; // TODO: auto pouplate application - author?: PublicUser; - member?: PublicMember; - mentions?: (PublicUser & { - member: PublicMember; - })[]; - mention_roles?: Role[]; - mention_channels?: Channel[]; - created_at?: Date; - // thread // TODO -} - -const PartialEmoji = { - id: String, - name: { type: String, required: true }, - animated: { type: Boolean, required: true }, -}; - -const MessageComponent: any = { - type: { type: Number, required: true }, - style: Number, - label: String, - emoji: PartialEmoji, - custom_id: String, - url: String, - disabled: Boolean, - components: [Object], -}; - -export interface MessageComponent { - type: number; - style?: number; - label?: string; - emoji?: PartialEmoji; - custom_id?: string; - url?: string; - disabled?: boolean; - components: MessageComponent[]; -} - -export enum MessageComponentType { - ActionRow = 1, - Button = 2, -} - -export interface MessageDocument extends Document, Message { - id: string; -} - -export enum MessageType { - DEFAULT = 0, - RECIPIENT_ADD = 1, - RECIPIENT_REMOVE = 2, - CALL = 3, - CHANNEL_NAME_CHANGE = 4, - CHANNEL_ICON_CHANGE = 5, - CHANNEL_PINNED_MESSAGE = 6, - GUILD_MEMBER_JOIN = 7, - USER_PREMIUM_GUILD_SUBSCRIPTION = 8, - USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9, - USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10, - USER_PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11, - CHANNEL_FOLLOW_ADD = 12, - GUILD_DISCOVERY_DISQUALIFIED = 14, - GUILD_DISCOVERY_REQUALIFIED = 15, - REPLY = 19, - APPLICATION_COMMAND = 20, -} - -export interface Attachment { - id: string; // attachment id - filename: string; // name of file attached - size: number; // size of file in bytes - url: string; // source url of file - proxy_url: string; // a proxied url of file - height?: number; // height of file (if image) - width?: number; // width of file (if image) - content_type?: string; -} - -export interface Embed { - title?: string; //title of embed - type?: EmbedType; // type of embed (always "rich" for webhook embeds) - description?: string; // description of embed - url?: string; // url of embed - timestamp?: Date; // timestamp of embed content - color?: number; // color code of the embed - footer?: { - text: string; - icon_url?: string; - proxy_icon_url?: string; - }; // footer object footer information - image?: EmbedImage; // image object image information - thumbnail?: EmbedImage; // thumbnail object thumbnail information - video?: EmbedImage; // video object video information - provider?: { - name?: string; - url?: string; - }; // provider object provider information - author?: { - name?: string; - url?: string; - icon_url?: string; - proxy_icon_url?: string; - }; // author object author information - fields?: { - name: string; - value: string; - inline?: boolean; - }[]; -} - -export enum EmbedType { - rich = "rich", - image = "image", - video = "video", - gifv = "gifv", - article = "article", - link = "link", -} - -export interface EmbedImage { - url?: string; - proxy_url?: string; - height?: number; - width?: number; -} - -export interface Reaction { - count: number; - //// not saved in the database // me: boolean; // whether the current user reacted using this emoji - emoji: PartialEmoji; - user_ids: string[]; -} - -export interface PartialEmoji { - id?: string; - name: string; - animated?: boolean; -} - -export interface AllowedMentions { - parse?: ("users" | "roles" | "everyone")[]; - roles?: string[]; - users?: string[]; - replied_user?: boolean; -} - -export const Attachment = { - id: String, // attachment id - filename: String, // name of file attached - size: Number, // size of file in bytes - url: String, // source url of file - proxy_url: String, // a proxied url of file - height: Number, // height of file (if image) - width: Number, // width of file (if image) - content_type: String, -}; - -export const EmbedImage = { - url: String, - proxy_url: String, - height: Number, - width: Number, -}; - -const Reaction = { - count: Number, - user_ids: [String], - emoji: { - id: String, - name: String, - animated: Boolean, - }, -}; - -export const Embed = { - title: String, //title of embed - type: { type: String }, // type of embed (always "rich" for webhook embeds) - description: String, // description of embed - url: String, // url of embed - timestamp: Date, // timestamp of embed content - color: Number, // color code of the embed - footer: { - text: String, - icon_url: String, - proxy_icon_url: String, - }, // footer object footer information - image: EmbedImage, // image object image information - thumbnail: EmbedImage, // thumbnail object thumbnail information - video: EmbedImage, // video object video information - provider: { - name: String, - url: String, - }, // provider object provider information - author: { - name: String, - url: String, - icon_url: String, - proxy_icon_url: String, - }, // author object author information - fields: [ - { - name: String, - value: String, - inline: Boolean, - }, - ], -}; - -export const MessageSchema = new Schema({ - id: String, - channel_id: String, - author_id: String, - webhook_id: String, - guild_id: String, - application_id: String, - content: String, - timestamp: Date, - edited_timestamp: Date, - tts: Boolean, - mention_everyone: Boolean, - mention_user_ids: [String], - mention_role_ids: [String], - mention_channel_ids: [String], - attachments: [Attachment], - embeds: [Embed], - reactions: [Reaction], - nonce: Schema.Types.Mixed, // can be a long or a string - pinned: Boolean, - type: { type: Number }, - activity: { - type: { type: Number }, - party_id: String, - }, - flags: Types.Long, - stickers: [], - message_reference: { - message_id: String, - channel_id: String, - guild_id: String, - }, - components: [MessageComponent], - // virtual: - // author: { - // ref: UserModel, - // localField: "author_id", - // foreignField: "id", - // justOne: true, - // autopopulate: { select: { id: true, user_data: false } }, - // }, -}); - -MessageSchema.virtual("author", { - ref: UserModel, - localField: "author_id", - foreignField: "id", - justOne: true, - autopopulate: { select: PublicUserProjection }, -}); - -MessageSchema.virtual("member", { - ref: MemberModel, - localField: "author_id", - foreignField: "id", - justOne: true, -}); - -MessageSchema.virtual("mentions", { - ref: UserModel, - localField: "mention_user_ids", - foreignField: "id", - justOne: false, - autopopulate: { select: PublicUserProjection }, -}); - -MessageSchema.virtual("mention_roles", { - ref: RoleModel, - localField: "mention_role_ids", - foreignField: "id", - justOne: false, - autopopulate: true, -}); - -MessageSchema.virtual("mention_channels", { - ref: RoleModel, - localField: "mention_channel_ids", - foreignField: "id", - justOne: false, - autopopulate: { select: { id: true, guild_id: true, type: true, name: true } }, -}); - -MessageSchema.virtual("referenced_message", { - ref: "Message", - localField: "message_reference.message_id", - foreignField: "id", - justOne: true, - autopopulate: true, -}); - -MessageSchema.virtual("created_at").get(function (this: MessageDocument) { - return new Date(Snowflake.deconstruct(this.id).timestamp); -}); - -MessageSchema.set("removeResponse", ["mention_channel_ids", "mention_role_ids", "mention_user_ids", "author_id"]); - -// TODO: missing Application Model -// MessageSchema.virtual("application", { -// ref: Application, -// localField: "mention_role_ids", -// foreignField: "id", -// justOne: true, -// }); - -// @ts-ignore -export const MessageModel = db.model("Message", MessageSchema, "messages"); diff --git a/rtc/src/models/RateLimit.ts b/rtc/src/models/RateLimit.ts deleted file mode 100644 index 6a0e1ffd..00000000 --- a/rtc/src/models/RateLimit.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Schema, Document, Types } from "mongoose"; -import db from "../util/Database"; - -export interface Bucket { - id: "global" | "error" | string; // channel_239842397 | guild_238927349823 | webhook_238923423498 - user_id: string; - hits: number; - blocked: boolean; - expires_at: Date; -} - -export interface BucketDocument extends Bucket, Document { - id: string; -} - -export const BucketSchema = new Schema({ - id: { type: String, required: true }, - user_id: { type: String, required: true }, // bot, user, oauth_application, webhook - hits: { type: Number, required: true }, // Number of times the user hit this bucket - blocked: { type: Boolean, required: true }, - expires_at: { type: Date, required: true }, -}); - -// @ts-ignore -export const BucketModel = db.model("Bucket", BucketSchema, "ratelimits"); diff --git a/rtc/src/models/ReadState.ts b/rtc/src/models/ReadState.ts deleted file mode 100644 index 9c4fb323..00000000 --- a/rtc/src/models/ReadState.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { PublicMember } from "./Member"; -import { Schema, model, Types, Document } from "mongoose"; -import db from "../util/Database"; - -export interface ReadState extends Document { - message_id: string; - channel_id: string; - user_id: string; - last_message_id?: string; - last_pin_timestamp?: Date; - mention_count: number; - manual: boolean; -} - -export const ReadStateSchema = new Schema({ - message_id: String, - channel_id: String, - user_id: String, - last_message_id: String, - last_pin_timestamp: Date, - mention_count: Number, - manual: Boolean, -}); - -// @ts-ignore -export const ReadStateModel = db.model("ReadState", ReadStateSchema, "readstates"); diff --git a/rtc/src/models/Role.ts b/rtc/src/models/Role.ts deleted file mode 100644 index c1111c84..00000000 --- a/rtc/src/models/Role.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Schema, model, Types, Document } from "mongoose"; -import db from "../util/Database"; -import toBigInt from "../util/toBigInt"; - -export interface Role { - id: string; - guild_id: string; - color: number; - hoist: boolean; - managed: boolean; - mentionable: boolean; - name: string; - permissions: bigint; - position: number; - tags?: { - bot_id?: string; - }; -} - -export interface RoleDocument extends Document, Role { - id: string; -} - -export const RoleSchema = new Schema({ - id: String, - guild_id: String, - color: Number, - hoist: Boolean, - managed: Boolean, - mentionable: Boolean, - name: String, - permissions: { type: String, get: toBigInt }, - position: Number, - tags: { - bot_id: String, - }, -}); - -RoleSchema.set("removeResponse", ["guild_id"]); - -// @ts-ignore -export const RoleModel = db.model("Role", RoleSchema, "roles"); diff --git a/rtc/src/models/Status.ts b/rtc/src/models/Status.ts deleted file mode 100644 index 5a9bf2ca..00000000 --- a/rtc/src/models/Status.ts +++ /dev/null @@ -1,13 +0,0 @@ -export type Status = "idle" | "dnd" | "online" | "offline"; - -export interface ClientStatus { - desktop?: string; // e.g. Windows/Linux/Mac - mobile?: string; // e.g. iOS/Android - web?: string; // e.g. browser, bot account -} - -export const ClientStatus = { - desktop: String, - mobile: String, - web: String, -}; diff --git a/rtc/src/models/Team.ts b/rtc/src/models/Team.ts deleted file mode 100644 index 795c82d2..00000000 --- a/rtc/src/models/Team.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface Team { - icon: string | null; - id: string; - members: { - membership_state: number; - permissions: string[]; - team_id: string; - user_id: string; - }[]; - name: string; - owner_user_id: string; -} - -export enum TeamMemberState { - INVITED = 1, - ACCEPTED = 2, -} diff --git a/rtc/src/models/Template.ts b/rtc/src/models/Template.ts deleted file mode 100644 index ad0f9104..00000000 --- a/rtc/src/models/Template.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Schema, model, Types, Document } from "mongoose"; -import db from "../util/Database"; -import { PublicUser, User, UserModel, PublicUserProjection } from "./User"; -import { Guild, GuildModel } from "./Guild"; - -export interface Template extends Document { - id: string; - code: string; - name: string; - description?: string; - usage_count?: number; - creator_id: string; - creator: User; - created_at: Date; - updated_at: Date; - source_guild_id: String; - serialized_source_guild: Guild; -} - -export const TemplateSchema = new Schema({ - id: String, - code: String, - name: String, - description: String, - usage_count: Number, - creator_id: String, - created_at: Date, - updated_at: Date, - source_guild_id: String, -}); - -TemplateSchema.virtual("creator", { - ref: UserModel, - localField: "creator_id", - foreignField: "id", - justOne: true, - autopopulate: { - select: PublicUserProjection, - }, -}); - -TemplateSchema.virtual("serialized_source_guild", { - ref: GuildModel, - localField: "source_guild_id", - foreignField: "id", - justOne: true, - autopopulate: true, -}); - -// @ts-ignore -export const TemplateModel = db.model