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 new file mode 100644 index 00000000..32ef9beb --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_STORE +db/ +dist/ +node_modules \ No newline at end of file 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/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/bundle/tsconfig.json b/bundle/tsconfig.json new file mode 100644 index 00000000..6bf2e6b7 --- /dev/null +++ b/bundle/tsconfig.json @@ -0,0 +1,68 @@ +{ + "include": ["src/**/*.ts"], + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "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. */, + "checkJs": true /* Report errors in .js files. */, + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true /* Generates corresponding '.d.ts' file. */, + "declarationMap": false /* Generates a sourcemap for each corresponding '.d.ts' file. */, + "sourceMap": true /* Generates corresponding '.map' file. */, + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist/" /* Redirect output structure to the directory. */, + "rootDir": "./src/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, + "strictNullChecks": true /* Enable strict null checks. */, + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + "strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */, + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */, + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "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. */, + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same 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/util/package.json b/util/package.json index 0478fe69..69af0f26 100644 --- a/util/package.json +++ b/util/package.json @@ -5,9 +5,7 @@ "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" + "build": "tsc -b ." }, "repository": { "type": "git",