Add backend

This commit is contained in:
schmelczerandras 2020-10-04 19:05:32 +02:00
parent 4ad60813c9
commit 0f0a1eaf67
19 changed files with 355 additions and 45 deletions

1
backend/.eslintignore Normal file
View file

@ -0,0 +1 @@
**/*.js

29
backend/.eslintrc.json Normal file
View file

@ -0,0 +1,29 @@
{
"root": true,
"env": {
"browser": true,
"es2020": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
"prettier/@typescript-eslint"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 11,
"sourceType": "module"
},
"plugins": ["unused-imports", "@typescript-eslint", "prettier"],
"rules": {
"prettier/prettier": "error",
"no-unused-vars": "off",
"unused-imports/no-unused-imports-ts": "error",
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-non-null-assertion": "off"
}
}

4
backend/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
dist
node_modules
package-lock.json
.firebase

7
backend/.prettierrc Normal file
View file

@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"printWidth": 90,
"tabWidth": 2,
"singleQuote": true,
"endOfLine": "lf"
}

51
backend/package.json Normal file
View file

@ -0,0 +1,51 @@
{
"name": "decla.red-server",
"version": "0.0.0",
"description": "Game server for decla.red",
"private": true,
"main": "index.js",
"scripts": {
"start": "concurrently --kill-others \"webpack --mode development -w\" \"npx nodemon dist/main.js\"",
"lint": "npx eslint --fix \"src/**/*.ts\" && npx prettier --write \"src/**/*.ts\"",
"build": "webpack --mode production"
},
"keywords": [],
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
"devDependencies": {
"@types/express": "^4.17.8",
"@types/gl-matrix": "^2.4.5",
"@types/node": "^14.11.2",
"@types/uuid": "^8.0.0",
"@typescript-eslint/eslint-plugin": "^3.9.1",
"@typescript-eslint/parser": "^3.9.1",
"clean-webpack-plugin": "^3.0.0",
"concurrently": "^5.3.0",
"eslint": "^7.2.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.21.2",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-unused-imports": "^0.1.3",
"firebase": "^7.22.0",
"gl-matrix": "^3.3.0",
"nodemon": "^2.0.4",
"prettier": "^2.0.5",
"terser-webpack-plugin": "^2.3.5",
"ts-loader": "^8.0.1",
"typescript": "^3.8.3",
"uuid": "^8.2.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3",
"file-loader": "^6.1.0"
},
"dependencies": {
"@types/cors": "^2.8.7",
"@types/socket.io": "^2.1.11",
"cors": "^2.8.5",
"express": "^4.17.1",
"http": "0.0.1-security",
"socket.io": "^2.3.0",
"uws": "^10.148.1",
"webpack-node-externals": "^2.5.2"
}
}

29
backend/src/index.html Normal file
View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.1/socket.io.js"
integrity="sha512-AcZyhRP/tbAEsXCCGlziPun5iFvcSUpEz2jKkx0blkYKbxU81F+iq8FURwPn1sYFeksJ+sDDrI5XujsqSobWdQ=="
crossorigin="anonymous"
></script>
<title>Server info</title>
</head>
<body></body>
<script>
const socket = io({
transports: ['websocket'],
});
socket.on('reconnect_attempt', () => {
socket.io.opts.transports = ['polling', 'websocket'];
});
socket.emit('join', 'insights');
socket.on('insights', (message) => {
document.body.innerText += message;
});
</script>
</html>

61
backend/src/main.ts Normal file
View file

@ -0,0 +1,61 @@
import ioserver, { Socket } from 'socket.io';
import express from 'express';
import { Server } from 'http';
import cors from 'cors';
import { PlayerContainer } from './players/player-container';
import './index.html';
import { TransportEvents } from '../../shared/src/transport/transport-events';
import { Player } from './players/player';
const app = express();
app.use(
cors({
origin: (origin, callback) => {
callback(null, true);
},
credentials: true,
})
);
const port = 3000;
const server = new Server(app);
const io = ioserver(server);
const players = new PlayerContainer();
const log = (text: string) => {
io.to('insights').emit('insights', text + '\n');
};
app.get('/', function (req, res) {
res.sendFile('dist/index.html', { root: '.' });
});
io.on('connection', (socket: SocketIO.Socket) => {
socket.on(TransportEvents.PlayerJoining, () => {
log('player joined');
const player = new Player(socket);
players.addPlayer(player);
socket.on(TransportEvents.PlayerSendingInfo, () => {});
socket.on('disconnect', () => {
log('player disconnected');
players.removePlayerBySocketId(player.socketId);
});
});
socket.on('join', (room_name: string) => {
socket.join(room_name);
});
//socket.on('disconnect', () => {});
});
server.listen(port, () => {
console.log(`server started at http://localhost:${port}`);
});

View file

@ -0,0 +1,13 @@
import { Player } from './player';
export class PlayerContainer {
private socketIdToPlayer = new Map<string, Player>();
public addPlayer(player: Player) {
this.socketIdToPlayer.set(player.socketId, player);
}
public removePlayerBySocketId(socketId: string) {
this.socketIdToPlayer.delete(socketId);
}
}

View file

@ -0,0 +1,9 @@
import { Socket } from 'dgram';
export class Player {
constructor(private readonly socket: SocketIO.Socket) {}
public get socketId(): string {
return this.socket.id;
}
}

19
backend/tsconfig.json Normal file
View file

@ -0,0 +1,19 @@
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": false,
"target": "es6",
"downlevelIteration": true,
"allowJs": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"module": "commonjs",
"esModuleInterop": true,
"baseUrl": ".",
"paths": {
"*": ["node_modules/*"]
}
},
"include": ["src/**/*"]
}

75
backend/webpack.config.js Normal file
View file

@ -0,0 +1,75 @@
const path = require('path');
const TerserJSPlugin = require('terser-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const PATHS = {
entryPoint: path.resolve(__dirname, 'src/main.ts'),
bundles: path.resolve(__dirname, 'dist'),
};
module.exports = {
entry: {
main: [PATHS.entryPoint],
},
externals: [nodeExternals()],
target: 'node',
output: {
filename: '[name].js',
path: PATHS.bundles,
},
devtool: 'source-map',
watchOptions: {
aggregateTimeout: 600,
ignored: /node_modules/,
},
optimization: {
minimize: true,
usedExports: true,
minimizer: [
new TerserJSPlugin({
sourceMap: true,
cache: true,
test: /\.ts$/i,
terserOptions: {
ecma: 5,
warnings: true,
parse: {},
compress: { defaults: true },
mangle: true,
module: false,
output: null,
toplevel: true,
nameCache: null,
ie8: false,
keep_classnames: false,
keep_fnames: false,
safari10: false,
},
}),
],
},
module: {
rules: [
{
test: /\.html$/i,
use: {
loader: 'file-loader',
query: {
outputPath: '/',
name: '[name].[ext]',
},
},
},
{
test: /\.ts$/,
use: {
loader: 'ts-loader',
},
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.ts', '.js'],
},
};