diff --git a/_scripts/bootstrap.sh b/_scripts/bootstrap.sh index d093f534c..b6541097f 100755 --- a/_scripts/bootstrap.sh +++ b/_scripts/bootstrap.sh @@ -2,8 +2,6 @@ set -eo pipefail -echo "Moving example config files into usable places." - # https://stackoverflow.com/questions/59895/how-can-i-get-the-directory-where-a-bash-script-is-located-from-within-the-scrip # if you actually think bash is a good programming language you are # *straight up delusional* @@ -12,12 +10,93 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) cd "$SCRIPT_DIR"; cd ..; -cp client/.example.env client/.env +function mvExampleFiles { + echo "Moving example config files into usable places..." -cp server/test.conf.json5 server/conf.json5 -cp server/.example.env server/.env + cp client/example/.env client/.env -cp bot/example/conf.json5 bot/conf.json5 -cp bot/example/example.env bot/.env + cp server/example/conf.json5 server/conf.json5 + cp server/example/.env server/.env -echo "Done." \ No newline at end of file + cp bot/example/conf.json5 bot/conf.json5 + cp bot/example/example.env bot/.env + + echo "Moved!" +} + +function selfSignHTTPS { + echo "Self-Signing HTTPS Certificates for local-dev server..." + + # This is for dev servers only! You should use this to + # create a self-signed HTTPS certificate for local dev. + # That is it. This is not secure. + mkdir -p server/cert + + openssl req -x509 -newkey rsa:4096 -keyout server/cert/key.pem -out server/cert/cert.pem -sha256 -days 365 -nodes -subj "/C=AU/ST=TachiExample/L=TachiExample/O=TachiExample/CN=127.0.0.1" &> /dev/null + + echo "Created HTTPS Certificates!" +} + +function pnpmInstall { + echo "Installing dependencies..." + + if ! command -v pnpm &> /dev/null + then + echo "Couldn't find pnpm. Can't install dependencies. Install it with npm install -g pnpm." + exit 1 + fi + + pnpm install + + echo "Installed dependencies." +} + +function startServices { + echo "Starting MongoDB Service..." + + systemctl start mongodb.service + + echo "MongoDB is running." + + echo "Starting Redis..." + + redis-server --daemonize yes + + echo "Redis is running." +} + +function syncDatabaseWithSeeds { + echo "Syncing database with seeds..." + + cd server + + pnpm run sync-database + + echo "Synced." +} + +mvExampleFiles +selfSignHTTPS +pnpmInstall +startServices +syncDatabaseWithSeeds + + +tput setaf 1 + +cat << EOF +=== READ THIS YOU MUPPET === + +YOU ARE USING SELF-SIGNED HTTPS CERTIFICATES. +YOU WILL LIKELY HAVE TO GO TO HTTPS://127.0.0.1:8080 AFTER STARTING TACHI-SERVER. +TELL YOUR BROWSER THESE CERTIFICATES ARE TRUSTED! +OTHERWISE, THE CLIENT WILL FAIL TO LAUNCH, AND WILL JUST BE A WHITE PAGE! +EOF + +tput sgr0 + +cat << EOF +Bootstrapped. +Launch the server with pnpm start-server. +Launch the client with pnpm start-client. +EOF diff --git a/client/.gitignore b/client/.gitignore index 81d028527..1367dd6db 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,2 +1,4 @@ # compiled react output -build \ No newline at end of file +build + +!example/** \ No newline at end of file diff --git a/client/.example.env b/client/example/.env similarity index 100% rename from client/.example.env rename to client/example/.env diff --git a/package.json b/package.json index 2ddf5ba19..5083a5fd6 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,10 @@ "private": true, "description": "The root of the Tachi monorepo. Contains common utils like linters.", "scripts": { - "lint": "eslint . --ext .ts --fix" + "lint": "eslint . --ext .ts --fix", + "start-client": "pnpm --filter ./client start", + "start-server": "pnpm --filter ./server start", + "start-score-import-worker": "pnpm --filter ./server runscoreworker" }, "repository": { "type": "git", diff --git a/server/.gitignore b/server/.gitignore index 773ceb0e1..46a36aada 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -14,4 +14,4 @@ local-cdn test-cdn !test.conf.json5 -!.example.env \ No newline at end of file +!example/** \ No newline at end of file diff --git a/server/.example.env b/server/example/.env similarity index 100% rename from server/.example.env rename to server/example/.env diff --git a/server/example/conf.json5 b/server/example/conf.json5 new file mode 100644 index 000000000..a8dba3af9 --- /dev/null +++ b/server/example/conf.json5 @@ -0,0 +1,88 @@ +// Config file that the CI deployment uses. This is moved to $pwd/conf.json5 before CI tests are ran. + +{ + MONGO_DATABASE_NAME: "localdb", + CAPTCHA_SECRET_KEY: "unused", + SESSION_SECRET: "unused", + FLO_API_URL: "https://flo.example.com", + EAG_API_URL: "https://eag.example.com", + MIN_API_URL: "https://min.example.com", + ARC_API_URL: "https://arc.example.com", + FLO_OAUTH2_INFO: { + CLIENT_ID: "DUMMY_CLIENT_ID", + CLIENT_SECRET: "DUMMY_CLIENT_SECRET", + REDIRECT_URI: "https://example.com", + }, + EAG_OAUTH2_INFO: { + CLIENT_ID: "DUMMY_CLIENT_ID", + CLIENT_SECRET: "DUMMY_CLIENT_SECRET", + REDIRECT_URI: "https://example.com", + }, + ARC_AUTH_TOKEN: "unused", + OUR_URL: "http://127.0.0.1:8080/", + CLIENT_DEV_SERVER: "http://127.0.0.1:3000", + ENABLE_SERVER_HTTPS: true, + OPTIONS_ALWAYS_SUCCEEDS: true, + INVITE_CODE_CONFIG: { + BATCH_SIZE: 2, + INVITE_CAP: 100, + BETA_USER_BONUS: 5, + }, + CDN_CONFIG: { + WEB_LOCATION: "https://127.0.0.1:8080/cdn", + SAVE_LOCATION: { + TYPE: "LOCAL_FILESYSTEM", + LOCATION: "./local-cdn", + SERVE_OWN_CDN: true, + }, + }, + TACHI_CONFIG: { + TYPE: "omni", + NAME: "Tachi Local Dev", + GAMES: [ + "iidx", + "museca", + "maimai", + "sdvx", + "ddr", + "bms", + "chunithm", + "usc", + "wacca", + "popn", + "jubeat", + "pms", + ], + IMPORT_TYPES: [ + "file/eamusement-iidx-csv", + "file/batch-manual", + "file/solid-state-squad", + "file/mer-iidx", + "file/pli-iidx-csv", + "ir/direct-manual", + "ir/barbatos", + "ir/fervidex", + "ir/fervidex-static", + "ir/beatoraja", + "ir/usc", + "ir/kshook-sv6c", + "api/arc-iidx", + "api/arc-sdvx", + "api/eag-iidx", + "api/eag-sdvx", + "api/flo-iidx", + "api/flo-sdvx", + "api/min-sdvx", + ], + }, + LOGGER_CONFIG: { + FILE: false, + CONSOLE: true, + LOG_LEVEL: "info", + }, + SEEDS_CONFIG: { + REPO_URL: "https://github.com/TNG-dev/Tachi", + USER_NAME: null, + USER_EMAIL: null, + }, +} diff --git a/server/package.json b/server/package.json index 4bb22876c..43115b9c6 100644 --- a/server/package.json +++ b/server/package.json @@ -11,9 +11,10 @@ "build": "tsc --project tsconfig.build.json", "typecheck": "tsc --project tsconfig.build.json --noEmit", "lint": "eslint ./src --ext .ts --fix", - "start": "tsc --project tsconfig.build.json && pnpm start-no-build", + "start": "pnpm build && pnpm start-no-build", "start-no-build": "node -r ts-node/register -r tsconfig-paths/register js/server/src/main.js", - "runscoreworker": "node -r ts-node/register -r tsconfig-paths/register js/server/src/lib/score-import/worker/worker.js" + "runscoreworker": "node -r ts-node/register -r tsconfig-paths/register js/server/src/lib/score-import/worker/worker.js", + "sync-database": "ts-node src/scripts/sync-database" }, "author": "zkldi", "license": "AGPL3", diff --git a/server/scripts/make-selfsigned-https.sh b/server/scripts/make-selfsigned-https.sh deleted file mode 100755 index e7633657c..000000000 --- a/server/scripts/make-selfsigned-https.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash - -# This command is for dev servers only! You should use this to -# create a self-signed HTTPS certificate for local dev. -# That is it. This is not secure. -mkdir -p cert - -yes "" | openssl req -x509 -newkey rsa:4096 -keyout ./cert/key.pem -out ./cert/cert.pem -sha256 -days 365 --nodes &> /dev/null - -echo "Created HTTPS Certificates!" \ No newline at end of file diff --git a/server/src/main.ts b/server/src/main.ts index dc8f34dda..70935d8c1 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -64,10 +64,13 @@ void RunOnInit(); let instance: http.Server | https.Server; if (ServerConfig.ENABLE_SERVER_HTTPS === true) { - logger.warn( - "HTTPS Mode is enabled. This should not be used in production, and you should instead run behind a reverse proxy.", - { bootInfo: true } - ); + if (Environment.nodeEnv === "production") { + logger.warn( + "HTTPS Mode is enabled. This should not be used in production, and you should instead run behind a reverse proxy.", + { bootInfo: true } + ); + } + const privateKey = fs.readFileSync("./cert/key.pem"); const certificate = fs.readFileSync("./cert/cert.pem"); diff --git a/server/src/scripts/sync-database.ts b/server/src/scripts/sync-database.ts index 49363f2c7..c1830faa0 100644 --- a/server/src/scripts/sync-database.ts +++ b/server/src/scripts/sync-database.ts @@ -38,7 +38,7 @@ interface SyncInstructions { ) => Promise; } -async function RemoveNotPresent( +async function RemoveNotPresent>( documents: Array, collection: ICollection, field: keyof T, @@ -58,7 +58,7 @@ async function RemoveNotPresent( } } -async function GenericUpsert( +async function GenericUpsert>( documents: Array, collection: ICollection, field: keyof T, @@ -387,5 +387,9 @@ async function SynchroniseDBWithSeeds() { if (require.main === module) { SynchroniseDBWithSeeds() .then(() => process.exit(0)) - .catch(() => process.exit(1)); + .catch((err) => { + logger.error(err, () => { + process.exit(1) + }) + }); } diff --git a/server/src/utils/db.ts b/server/src/utils/db.ts index f4754a950..7268a793f 100644 --- a/server/src/utils/db.ts +++ b/server/src/utils/db.ts @@ -83,28 +83,29 @@ export async function GetRelevantSongsAndCharts( } export async function UpdateGameSongIDCounter(game: "bms" | "pms") { - const largestSongID = await db.songs[game].findOne( + const latestSong = await db.songs[game].findOne( {}, { sort: { id: -1 }, projection: { id: 1 }, } - ); + ) - if (!largestSongID) { - logger.severe( - `No ${game} charts loaded, yet BMS sync was attempted? Lost state on ${game}-song-id counter. Panicking.` + if (!latestSong) { + logger.warn( + `No ${game} charts loaded, yet BMS sync was attempted? This was probably an initial setup, starting songIDs from 1.` ); - throw new Error(`No BMS charts loaded, yet BMS sync was attempted.`); } + let largestSongID = latestSong?.id ?? 0; + await db.counters.update( { counterName: `${game}-song-id`, }, { $set: { - value: largestSongID.id + 1, + value: largestSongID + 1, }, } );