Commit 532a5ce1 authored by Dennis Willers's avatar Dennis Willers 🏀

Merge branch 'dev-greep' into 'master'

Merge new backend API to Master

See merge request !1
parents d4df8b91 ad4e12d3
Pipeline #466 passed with stages
in 2 minutes and 22 seconds
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
}
}
{
// 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": [
{
"type": "pwa-node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\index.js"
}
]
}
\ No newline at end of file
FROM node:12.18.1 FROM node:lts
ENV NODE_ENV=production ENV NODE_ENV=production
EXPOSE 8080 EXPOSE 8080
EXPOSE 3000 EXPOSE 3000
......
...@@ -9,45 +9,93 @@ The client can connect to the socket server via `willers.digital` on port `3201` ...@@ -9,45 +9,93 @@ The client can connect to the socket server via `willers.digital` on port `3201`
If you just want to call the REST-Server you can do it with: `https://tm-voting.willers.digital`. If you just want to call the REST-Server you can do it with: `https://tm-voting.willers.digital`.
## REST Services ## REST Services
There are currently only two REST interfaces. **All parameters can be done in the url query `/getVotes?map=blah` or in the Body you sent in a JSON format `{"map":"blah"}`**
**POST /getMapInfo**<br> **GET /getVotes**<br>
Returns the current voting status for the current map.<br> Returns the current voting status for the current map.<br>
Example Request:
``` | Parameter | Type | Description | Example
|------------ |------- |------------------------------------- |-----------------------------
| map | String | The map UID to show the votes on it | `OkNwgzSwDLZSWSRPsUKY7EA1Cg5`
Example response:
```json
{ {
"mapId": "currentMapUId", "mapUid": "OkNwgzSwDLZSWSRPsUKY7EA1Cg5",
"userId": "UserLogin", "votes": 53,
"name": "mapname for example: Summer 2021 - 01" "average": 85,
"lastVoteDate": "2021-08-23T00:28:16.273Z"
} }
``` ```
Info: I heard that the name is not really relevant, because the API of trackmania.io already provides information about a map. Nevertheless, in the current implementation this field should at least not be null.
**POST /setVote**<br> **GET /getPlayerVote**<br>
Writes the vote of a player to the respective map into the database table. Returns the current voting status of a player for the current map.<br>
Example Request:
``` | Parameter | Type | Description | Example
|------------ |------- |------------------------------------- |-----------------------------
| map | String | The map UID to show the votes on it | `OkNwgzSwDLZSWSRPsUKY7EA1Cg5`
| player | String | The player login that he voted on it | `Jtmn3kBnSSadky_mLNhp_A`
Example response:
```json
{ {
"mapId": "currentMapUId", "mapUid": "OkNwgzSwDLZSWSRPsUKY7EA1Cg5",
"userId": "UserLogin", "playerLogin": "Jtmn3kBnSSadky_mLNhp_A",
"name": "mapname for example: Summer 2021 - 01", "vote": 50,
"vote": 40 "date": "2021-08-23 04:55:49.105"
} }
``` ```
**POST RESPONSE**<br>
The response is the same in both cases: **GET /mostVotedMaps**<br>
``` Returns the top most voted maps. in decreasing order (from the most voted map to the least voted map)<br>
There's no parameters for this request!
Example response:
```json
{ {
"votes": 3, "OkNwgzSwDLZSWSRPsUKY7EA1Cg5": 65,
"average": 63, "7fsfRSUCQ7YwfBEdRk_GivW6qzj": 56,
"vote": 80 "KOylxZkny8RdOEFhchN1kG6Uoo1": 32,
"n8KeykdPYEsJM6RPEZcQHVRVRIb": 32,
"RfGQDoOnJ0FiswOBjpL3V7nkF0a": 32,
"Iwo4gO_0dQ3FVQ1xeYjho5ZmLrf": 1,
} }
``` ```
If other players only listen to the current voting status on the map, the vote for the respective client is not returned, since this is client-specific and therefore not interesting for everyone. So for them the response will be like:
**GET /mostPlayerVoted**<br>
Returns the top of the players who have voted the most maps. in decreasing order (from the most player who voted to the least)<br>
There's no parameters for this request!
Example response:
```json
{
"Jtmn3kBnSSadky_mLNhp_A": 10,
"W01C9MLeQH2zZ8v_P-gXvA": 8,
"TIA7WqNETVyjWNj3RV1shQ": 5,
"c5jutptORLinoaIUmVWscA": 2,
"xTn1Lty3Tki8v7w3FBqVIA": 1
}
``` ```
**POST /setVote**<br>
Writes the vote of a player to the respective map into the database table.<br />
| Parameter | Type | Description | Example
|------------ |------- |------------------------------------- |-----------------------------
| map | String | The map UID to vote | `OkNwgzSwDLZSWSRPsUKY7EA1Cg5`
| player | String | The player login that it will vote | `Jtmn3kBnSSadky_mLNhp_A`
| vote | Number | A number between 0 and 100 to define the vote | `56`
Example Response:
```json
{ {
"votes": 3, "mapUid": "OkNwgzSwDLZSWSRPsUKY7EA1Cg5",
"average": 63 "player": "Jtmn3kBnSSadky_mLNhp_A",
"vote": 65,
"date": "2021-08-23T03:32:18.301Z",
"type": "update" // "new" if it's a new vote, "update" if the player already voted on this map before
} }
``` ```
...@@ -82,4 +130,4 @@ The following star scale was defined for the voting plugin: ...@@ -82,4 +130,4 @@ The following star scale was defined for the voting plugin:
## Attention ## Attention
My backend is really not secure for SQL-Injection and some other secure stuff. If some more people want to use it, I should protect it more.. but that take some time. You are welcome to help me with this. That would be a nice thing if we can introduce a global map vote functionality in a secure and highly available way. :) My backend is 100% not secure for SQL-Injection and some other secure stuff. If some more people want to use it, I should protect it more.. but that take some time. You are welcome to help me with this. That would be a nice thing if we can introduce a global map vote functionality in a secure and highly available way. :)
\ No newline at end of file \ No newline at end of file
const express = require('express');
function createRouter(db) {
const router = express.Router();
function isMapIdAndNameNotNull(req) {
const mapId = req.body.mapId;
const name = req.body.name;
return mapId != null && name != null;
}
function isVoteRequestValid(req) {
const userId = req.body.userId;
const vote = req.body.vote;
return userId != null && vote != null && isMapIdAndNameNotNull(req);
}
function isgetMapInfoValid(req) {
const userId = req.body.userId;
return userId != null && isMapIdAndNameNotNull(req);
}
const hasMap = function hasMap(req, res, next) {
const mapId = req.body.mapId;
if (isMapIdAndNameNotNull(req)) {
const sql = 'SELECT count(*) as Maps From Map WHERE mapId = \"'+mapId+'\";';
console.log('Map Select: ', sql);
db.query(
sql,
(error, results) => {
if (error) {
console.log(error);
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in hasMap'});
} else {
numberResults = results[0].Maps;
if (numberResults === 1) next();
else if (numberResults === 0) addMap(req, res, next);
else res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'There are multiple maps with the same id'});
}
});
} else {
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'JSON-Parameter are not valid'});
}
};
const addMap = function addMap(req, res, next) {
const mapId = req.body.mapId;
const name = req.body.name;
const sql = 'INSERT INTO Map (mapId, name) VALUES (\"'+mapId+'\", \"'+name+'\");';
console.log('Map Insert: ', sql);
db.query(
sql,
(error, results) => {
if (error) {
console.log(error);
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in addMap'});
} else {
if (results.affectedRows === 1) next();
else res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in insertMap'});
}
});
};
const hasVote = function hasVote(req, res, next) {
if (isVoteRequestValid(req)) {
const userId = req.body.userId;
const mapId = req.body.mapId;
const sql = 'SELECT userId FROM Vote WHERE userId = \"'+ userId + '\" AND mapId = \"' + mapId + '\";';
console.log('Map Insert: ', sql);
db.query(
sql,
(error, results) => {
if (error) {
console.log(error);
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in hasVote'});
} else {
if (results.length === 0) insertVote(req, res, next);
else if (results.length === 1) updateVote(req, res, next);
else res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'too many votes by user'});
}
});
} else {
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'Vote Request is not valid'});
}
};
const insertVote = function insertVote(req, res, next) {
if (isVoteRequestValid(req)) {
const userId = req.body.userId;
const mapId = req.body.mapId;
const vote = req.body.vote;
const sql = 'INSERT INTO Vote (userId, mapId, vote) VALUES (\"'+ userId + '\", \"'+ mapId + '\", \"' + vote +'\");';
console.log('Insert Vote: ', sql);
db.query(
sql,
(error, results) => {
if (error) {
console.log(error);
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in insertVote'});
} else {
if (results.affectedRows === 1) next();
else res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in insertVote'});
}
});
} else {
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'Vote Request is not valid'});
}
};
const updateVote = function updateVote(req, res, next) {
if (isVoteRequestValid(req)) {
const userId = req.body.userId;
const mapId = req.body.mapId;
const vote = req.body.vote;
const sql = 'UPDATE Vote SET userId = \"'+ userId + '\", mapId = \"'+ mapId + '\", vote = \"' + vote +'\" WHERE userID = \"'+ userId +'\" AND mapId = \"' + mapId + '\";';
console.log('Update Vote: ', sql);
db.query(
sql,
(error, results) => {
if (error) {
console.log(error);
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in updateVote'});
} else {
if (results.affectedRows === 1) next();
else res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in updateVote'});
}
});
} else {
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'Vote Request is not valid'});
}
};
const getMapInfo = function getMapInfo(req, res) {
if (isVoteRequestValid(req)) {
const mapId = req.body.mapId;
const vote = req.body.vote;
const sql = 'SELECT count(userId) as votes, round(avg(vote)) as average FROM Vote WHERE mapId LIKE \"'+ mapId + '\";';
console.log('getMapInfo: ', sql);
db.query(
sql,
(error, results) => {
if (error) {
console.log(error);
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in getMapInfo'});
} else {
if (results.length === 1) {
let average = results[0].average;
let votes = results[0].votes;
if (!average) average = 0;
if (!votes) votes = 0;
res.header('Access-Control-Allow-Origin', "*").status(200).json({votes: votes, average: average, vote: vote});
return;
}
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'unexpected result in getMapInfo'});
}
});
} else {
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'Vote Request is not valid'});
}
};
const getVote = function getVote(req, res) {
if (isgetMapInfoValid(req)) {
const mapId = req.body.mapId;
const userId = req.body.userId;
const sql = 'SELECT vote FROM Vote WHERE mapId LIKE \"'+ mapId + '\" AND userId LIKE \"' + userId + '\";';
console.log('Update Vote: ', sql);
db.query(
sql,
(error, results) => {
if (error) {
console.log(error);
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'error in getVote'});
} else {
if (results.length < 2) {
let vote = -1;
if (results.length === 1) {
vote = results[0].vote;
}
if (!isNaN(vote)) {
req.body.vote = vote;
getMapInfo(req, res);
return;
}
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'unexpected result in getVote'});
} else {
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'too many results in getVote'});
}
}
});
} else {
res.header('Access-Control-Allow-Origin', "*").status(500).json({status: 'Vote Request is not valid'});
}
};
const test = function test(req, res) {
res.header('Access-Control-Allow-Origin', "*").status(200).json({status: "Test valid!"});
};
// the routes are defined here
router.get('/test', [test]);
router.post('/setVote', [hasMap, hasVote, getMapInfo]);
router.post('/getMapInfo', [hasMap, getVote]);
return router;
}
module.exports = createRouter;
/* eslint-disable no-prototype-builtins */
const axios = require('axios'); const axios = require('axios');
/** /**
...@@ -17,7 +18,21 @@ function checkIfRequestHasVote(json) { ...@@ -17,7 +18,21 @@ function checkIfRequestHasVote(json) {
return JSON.parse(json).hasOwnProperty('vote'); return JSON.parse(json).hasOwnProperty('vote');
} }
function sendRequest(url, json, callback) { function sendGetRequest(url, callback) {
//make post request
axios
.get(url)
.then(res => {
//echo data
callback(res);
})
.catch(error => {
console.error(error);
callback(null);
});
}
function sendPostRequest(url, json, callback) {
//make post request //make post request
axios axios
.post(url, JSON.parse(json)) .post(url, JSON.parse(json))
...@@ -44,6 +59,7 @@ function addMapToClient(clientList, currentClient, mapId, callback) { ...@@ -44,6 +59,7 @@ function addMapToClient(clientList, currentClient, mapId, callback) {
module.exports = { module.exports = {
isJsonString, isJsonString,
checkIfRequestHasVote, checkIfRequestHasVote,
sendRequest, sendGetRequest,
sendPostRequest,
addMapToClient addMapToClient
}; };
require('./socket'); require('./socket');
require('dotenv').config(); require('dotenv').config();
const express = require('express'); const express = require('express'),
const cors = require('cors'); cors = require('cors'),
const bodyParser = require('body-parser'); logger = require('morgan'),
const mysql = require('mysql'); cookieParser = require('cookie-parser'),
const events = require('./events'); mysql = require('mysql'),
path = require('path'),
fs = require('fs');
const connection = mysql.createConnection({ const connection = mysql.createConnection({
host : process.env.DB_HOST, host : process.env.DB_HOST,
port : process.env.DB_PORT, port : process.env.DB_PORT,
...@@ -15,14 +17,79 @@ const connection = mysql.createConnection({ ...@@ -15,14 +17,79 @@ const connection = mysql.createConnection({
multipleStatements: true, multipleStatements: true,
}); });
connection.connect(); connection.connect((err)=>{
if (err){
console.error('Impossible to connect to MySQL server. Code: ' + err.code)
process.exit(1)
} else {
console.log('[SQL] Connected to the MySQL server! Connexion ID: ' + connection.threadId)
}
})
/**
* Render a JSON response for an error
* @param {import('express').Response} res
* @param {Number} status
* @param {String} message
*/
function renderError(res, status, message){
res.status(status || 500).json({
error: {
code: status || 500,
message: message
}
});
}
const port = process.env.PORT || 8080; const port = process.env.PORT || 8080;
const app = express() const app = express()
.disable('etag')
.use(cors()) .use(cors())
.use(bodyParser.json()) .use(express.json())
.use(events(connection)); .use(cookieParser())
.use(logger('(:date) :method :url - ":user-agent" (:remote-addr) - :status :response-time ms'));
// User-agent blacklist system (list on user-agent-blacklist.json)
app.use(function(req, res, next){
var ua = req.get('User-Agent')
if (!ua){
renderError(res, 403, "No User-Agent header found, please add a User-Agent header.")
} else {
var blacklistUA = JSON.parse(fs.readFileSync(path.join(__dirname, 'user-agent-blacklist.json')))
var blacklisted = false
blacklistUA.forEach(bUA=>{
if (ua.toLowerCase().includes(bUA.toLowerCase())){
blacklisted = true
}
});
if (blacklisted) {
console.log('BLACKLISTED UA: ' + ua)
renderError(res, 403, "Your User-Agent '"+ ua +"' is blacklisted, please change it.")
} else {
next()
}
}
});
app.get('/', (req, res) => {
let data = {online: true, routes: [], docs: 'https://git.willers.digital/Dennis.Willers/voting/blob/master/README.md'};
fs.readdirSync(path.join(__dirname, 'route')).filter(file => file.endsWith('.js')).forEach(function(file) {
data.routes.push(file.replace(/\.js$/i,''))
});
res.json(data);
})
fs.readdirSync(path.join(__dirname, 'route')).filter(file => file.endsWith('.js')).forEach(function(file) {
require(path.join(__dirname, 'route', file))(app, connection, renderError)
});
// catch 404 and forward to error handler
app.use(function(req, res) {
renderError(res, 404, "Not Found")
});
app.listen(port, () => { app.listen(port, () => {
console.log(`Express server listening on port ${port}`); console.log(`Express server listening on port ${port}`);
......
CREATE DATABASE IF NOT EXISTS `map-karma-api` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE `map-karma-api`;
DROP TABLE IF EXISTS `votes`;
CREATE TABLE IF NOT EXISTS `votes` (
`map` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
`player` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
`vote` int NOT NULL,
`date` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`map`),
UNIQUE KEY `player_map` (`map`(100),`player`(100)) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
This diff is collapsed.
{ {
"name": "Voting", "name": "tm2020-map-voting-api",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
...@@ -13,12 +13,17 @@ ...@@ -13,12 +13,17 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"mysql": "^2.18.1" "morgan": "^1.10.0",
"mysql": "^2.18.1",
"valid-url": "^1.0.9",
"trackmania.io": "^2.4.0"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^7.32.0",
"nodemon": "^2.0.7" "nodemon": "^2.0.7"
} }
} }
const path = require('path'),
scriptName = path.basename(__filename).replace(/\.js$/i,'');
/**
* @param {import('express').Express} app
* @param {import('mysql').Connection} sql
*/
module.exports = function(app, sql, errorHandler) {
app.get('/'+scriptName, function(req, res) {
const mapId = req.query.map || req.body.map,
player = req.query.player || req.body.player;
if (!mapId) {
return errorHandler(res, 400, 'Missing map id');
}
if (!player) {
return errorHandler(res, 400, 'Missing player login');
}
sql.query('SELECT * FROM votes WHERE map = ? AND player = ?', [mapId, player], (err, sqlRes)=>{
if (err) {
console.log(err);
errorHandler(res, 500, 'Internal server error');
} else {
if (sqlRes.length === 0) {
return res.json({
mapUid: mapId,
playerLogin: player,
vote: -1,
date: ""
});
}
if (sqlRes[0].map == null) {
return res.json({
mapUid: mapId,
playerLogin: player,
vote: -1,
date: ""
});
}
if (sqlRes[0].player == null) {
return res.json({
mapUid: mapId,
playerLogin: player,
vote: -1,
date: ""
});
}
res.json({
mapUid: sqlRes[0].map,
playerLogin: sqlRes[0].player,
vote: sqlRes[0].vote,
date: sqlRes[0].date
});
}
});
});
};
\ No newline at end of file
const path = require('path'),
scriptName = path.basename(__filename).replace(/\.js$/i,'');
/**
* @param {import('express').Express} app
* @param {import('mysql').Connection} sql
*/
module.exports = function(app, sql, errorHandler) {
app.get('/'+scriptName, function(req, res) {
const mapId = req.query.map || req.body.map;
if (!mapId) {
return errorHandler(res, 400, 'Missing map id');
}
sql.query('SELECT map, date, COUNT(*) AS count, round(avg(vote)) as average FROM votes WHERE map = ?', mapId, (err, sqlRes)=>{
if (err) {
console.log(err);
errorHandler(res, 500, 'Internal server error');
} else {
if (sqlRes[0].map == null) {
return res.json({
mapUid: mapId,
votes: 0,
average: 0,
lastVoteDate: ""
});
}
// Get the latest date from an array
const latestDate = new Date(Math.max.apply(null, sqlRes.map(function(e) {
return new Date(e.date);
})));
res.json({
mapUid: sqlRes[0].map,
votes: sqlRes[0].count,
average: sqlRes[0].average,
lastVoteDate: latestDate
});
}
});
});
};
\ No newline at end of file
const path = require('path'),
scriptName = path.basename(__filename).replace(/\.js$/i,'');
/**
* @param {import('express').Express} app
* @param {import('mysql').Connection} sql
*/
module.exports = function(app, sql, errorHandler) {
app.get('/'+scriptName, function(req, res) {
sql.query('SELECT player, COUNT(*) AS votes FROM votes GROUP BY player ORDER BY votes DESC', (err, sqlRes)=>{
if (err) {
console.log(err);
errorHandler(res, 500, 'Internal server error');
} else {
let votes = {};
for (let i = 0; i < sqlRes.length; i++) {
votes[sqlRes[i].player] = sqlRes[i].votes;
}
res.json(votes);
}
});
});
};
\ No newline at end of file
const path = require('path'),
scriptName = path.basename(__filename).replace(/\.js$/i,'');
/**
* @param {import('express').Express} app
* @param {import('mysql').Connection} sql
*/
module.exports = function(app, sql, errorHandler) {
app.get('/'+scriptName, function(req, res) {
sql.query('SELECT map, COUNT(*) AS votes FROM votes GROUP BY map ORDER BY votes DESC', (err, sqlRes)=>{
if (err) {
console.log(err);
errorHandler(res, 500, 'Internal server error');
} else {
let maps = {};
for (let i = 0; i < sqlRes.length; i++) {
maps[sqlRes[i].map] = sqlRes[i].votes;
}
res.json(maps);
}
});
});
};
\ No newline at end of file
const path = require('path'),
scriptName = path.basename(__filename).replace(/\.js$/i,''),
tmio = require('trackmania.io'),
tmioPlayer = new tmio.Players();
/**
* @param {import('express').Express} app
* @param {import('mysql').Connection} sql
*/
module.exports = function(app, sql, errorHandler) {
app.post('/'+scriptName, function(req, res) {
const mapId = req.query.map || req.body.map,
player = req.query.player || req.body.player,
vote = Number(req.query.vote || req.body.vote);
if (!mapId) return errorHandler(res, 400, 'Missing map id');
if (!player) return errorHandler(res, 400, 'Missing player login');
if (!vote) return errorHandler(res, 400, 'Missing vote');
if (isNaN(vote)) return errorHandler(res, 400, 'Invalid vote');
if (vote < 0 || vote > 100) return errorHandler(res, 400, 'Vote must be between 0 and 100');
// check if player exists (tmio API check)
tmioPlayer.player(player).then(()=>{
sql.query('SELECT * FROM votes WHERE map = ? AND player = ?', [mapId,player], (err, sqlRes)=>{
if (err) {
console.log(err);
errorHandler(res, 500, 'Internal server error');
} else {
const voteDate = new Date();
if (sqlRes.length === 0) { // Create a new vote for this player
sql.query('INSERT INTO votes (map, player, vote, date) VALUES (?, ?, ?, ?)', [mapId, player, vote, voteDate], (err)=>{
if (err) {
console.error(err);
errorHandler(res, 500, 'Internal server error');
} else {
res.json({
mapUid: mapId,
player: player,
vote: vote,
date: voteDate,
type: "new"
});
}
});
} else { // Update the vote for this player
sql.query('UPDATE votes SET vote = ?, date = ? WHERE map = ? AND player = ?', [vote, voteDate, mapId, player], (err)=>{
if (err) {
console.error(err);
errorHandler(res, 500, 'Internal server error');
} else {
res.json({
mapUid: mapId,
player: player,
vote: vote,
date: voteDate,
type: "update"
});
}
});
}
}
});
})
.catch((err)=>errorHandler(res, 400, err)); // player not found
});
};
const path = require('path'),
scriptName = path.basename(__filename).replace(/\.js$/i,'');
module.exports = function(app) {
app.get('/'+scriptName, function(req, res) {
res.json({status: "Test valid!"});
});
};
\ No newline at end of file
...@@ -72,32 +72,28 @@ server.on('connection',function(socket){ ...@@ -72,32 +72,28 @@ server.on('connection',function(socket){
console.log('Data sent to server : ' + data); console.log('Data sent to server : ' + data);
if(hf.isJsonString(data)) { if(hf.isJsonString(data)) {
let url; const req = JSON.parse(data);
if (hf.checkIfRequestHasVote(data)) { if (req['http'] === 'GET') {
url = 'http://localhost:8080/setVote'; hf.sendGetRequest('http://localhost:8080/' + req['url'], res => {
} else { hf.addMapToClient(clients, socket, req['map'], newClientList => {
url ='http://localhost:8080/getMapInfo';
}
hf.sendRequest(url, data, res => {
if (res) {
const req = JSON.parse(data);
hf.addMapToClient(clients, socket, req['mapId'], newClientList => {
clients = newClientList.slice(); clients = newClientList.slice();
socket.write(JSON.stringify(res.data) + '\n'); socket.write(JSON.stringify(res.data) + '\n');
if (hf.checkIfRequestHasVote(data)) {
sendToAllClientsAtSameMap(res, req['mapId'], socket);
}
}); });
//var is_kernel_buffer_full = socket.write(JSON.stringify(res.data) + '\n'); })
//if(is_kernel_buffer_full){ } else if (req['http'] === 'POST') {
// console.log('Data was flushed successfully from kernel buffer i.e written successfully!'); hf.sendPostRequest('http://localhost:8080/setVote', data, res => {
//} else { if (res) {
// socket.pause(); hf.addMapToClient(clients, socket, req['map'], newClientList => {
//} clients = newClientList.slice();
} else { socket.write(JSON.stringify(res.data) + '\n');
console.log("Res was null"); sendToAllClientsAtSameMap(req['map'], socket);
} });
}); } else {
console.log("Res was null");
}
});
}
} }
}); });
...@@ -150,14 +146,16 @@ server.on('connection',function(socket){ ...@@ -150,14 +146,16 @@ server.on('connection',function(socket){
} }
// Send a message to all clients playing the same map // Send a message to all clients playing the same map
function sendToAllClientsAtSameMap(res, mapId, currentClient) { function sendToAllClientsAtSameMap(mapId, currentClient) {
console.log("JSON: ", JSON.stringify(res.data)); hf.sendGetRequest('http://localhost:8080/getVotes?map='+mapId, res => {
clients.forEach(function (client) { console.log("JSON: ", JSON.stringify(res.data));
const resJson = res.data; clients.forEach(function (client) {
delete resJson['vote']; const resJson = res.data;
if (client.mapId === mapId && client.name !== currentClient) client.write(JSON.stringify(resJson) + '\n'); delete resJson['vote'];
if (client.mapId === mapId && client.name !== currentClient) client.write(JSON.stringify(resJson) + '\n');
});
console.log("Write Message to all at " + mapId +": " + JSON.stringify(res.data));
}); });
console.log("Write Message to all at " + mapId +": " + JSON.stringify(res.data));
} }
}); });
...@@ -253,11 +251,15 @@ client.on('data',function(data){ ...@@ -253,11 +251,15 @@ client.on('data',function(data){
// open new node instance => and run it... // open new node instance => and run it...
// 87.78.129.86 | localhost // 87.78.129.86 | localhost
// Examples:
// getVotes: {"map":"OkNwgzSwDLZSWSRPsUKY7EA1Cg5","http":"GET","url":"getVotes?map=OkNwgzSwDLZSWSRPsUKY7EA1Cg5"}
// setVotes: {"http":"POST", "map": "OkNwgzSwDLZSWSRPsUKY7EA1Cg5", "player": "Jtmn3kBnSSadky_mLNhp_A", "vote": 50}
// getPlayerVote: {"map":"OkNwgzSwDLZSWSRPsUKY7EA1Cg5","http":"GET","url":"getPlayerVote?map=OkNwgzSwDLZSWSRPsUKY7EA1Cg5&player=Jtmn3kBnSSadky_mLNhp_A"}
/*const testClient = net.connect({host: '87.78.129.86', port: 3201}, () => { const testClient = net.connect({host: 'localhost', port: 3000}, () => {
console.log('connected to server!'); console.log('connected to server!');
//testClient.write('Hello World Client!\r\n'); //testClient.write('Hello World Client!\r\n');
testClient.write(JSON.stringify({"mapId":"7fsfRSUCQ7YwfBEdRk_GivW6qzj","userId":"aKBNg9fbReqLedLiz1KFfA","name":"Summer 2021 - 01"})); testClient.write(JSON.stringify({"http":"POST", "map": "OkNwgzSwDLZSWSRPsUKY7EA1Cg5", "player": "Jtmn3kBnSSadky_mLNhp_A", "vote": 80}));
//test(testClient); //test(testClient);
}); });
......
[
"curl",
"wget"
]
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment