From b5cce7e127d27b00ad877b6bc56f8fd4fff64b1d Mon Sep 17 00:00:00 2001 From: Felix Date: Tue, 16 Aug 2016 13:40:47 +0200 Subject: [PATCH] Isomorphic mysql db, updates - Isomorphic databases - Refactored some player->db keys - Seperated shutdown method - Nearby pidgey instead of rattata - Removed some unused arguments - Player saving is async now - Prettified used db console print --- cfg.js | 3 +- src/db/mongo.js | 92 +++++++++---- src/db/mysql.js | 174 ++++++++++++++++++++++++- src/index.js | 40 +++++- src/packets/Responses.GetMapObjects.js | 4 +- src/packets/Responses.GetPlayer.js | 25 ++-- src/player.js | 118 ++++++----------- src/process.js | 9 +- src/response.js | 25 +++- src/setup.js | 30 +---- 10 files changed, 356 insertions(+), 164 deletions(-) diff --git a/cfg.js b/cfg.js index 68d8e9f..f22c2d1 100644 --- a/cfg.js +++ b/cfg.js @@ -15,7 +15,6 @@ export const SERVER_LOG_REQUESTS = true; export const SERVER_DEFAULT_CONSOLE_COLOR = 32; // Either mongo or mysql -// Dont use mysql right now export const SERVER_USE_DATABASE = "MONGO"; // MONGODB @@ -23,7 +22,6 @@ export const SERVER_MONGO_PORT = 27017; export const SERVER_MONGO_HOST_IP = "127.0.0.1"; export const SERVER_MONGO_DB_NAME = "pokemongo"; export const SERVER_MONGO_COLLECTION_USERS = "users"; -export const SERVER_MONGO_URL = `mongodb://${SERVER_MONGO_HOST_IP}:${SERVER_MONGO_PORT}/${SERVER_MONGO_DB_NAME}`; // MYSQL export const SERVER_MYSQL_PORT = 3306; @@ -31,6 +29,7 @@ export const SERVER_MYSQL_HOST_IP = "127.0.0.1"; export const SERVER_MYSQL_DB_NAME = "pogosql"; export const SERVER_MYSQL_USERNAME = "USERNAME"; export const SERVER_MYSQL_PASSWORD = "PASSWORD"; +export const SERVER_MYSQL_TABLE = "users"; // account used for pogo-asset-downloader lib export const SERVER_POGO_CLIENT_PROVIDER = "GOOGLE"; // either google or ptc diff --git a/src/db/mongo.js b/src/db/mongo.js index 4f17e80..eef5c7d 100644 --- a/src/db/mongo.js +++ b/src/db/mongo.js @@ -2,10 +2,12 @@ import mongodb from "mongodb"; import * as CFG from "../../cfg"; -export function setupMongo() { +export function setupConnection() { + + let url = `mongodb://${CFG.SERVER_MONGO_HOST_IP}:${CFG.SERVER_MONGO_PORT}/${CFG.SERVER_MONGO_DB_NAME}`; return new Promise((resolve) => { - mongodb.MongoClient.connect(CFG.SERVER_MONGO_URL, (error, db) => { + mongodb.MongoClient.connect(url, (error, db) => { if (error) { this.print(error, 31); } else { @@ -19,6 +21,18 @@ export function setupMongo() { } +/** + * @param {Function} resolve + */ +export function closeConnection(resolve) { + this.db.instance.close(() => { + resolve(); + }); +} + +/** + * @param {String} name + */ export function loadCollection(name) { return new Promise((resolve) => { @@ -34,6 +48,9 @@ export function loadCollection(name) { } +/** + * @param {String} name + */ export function createCollection(name) { return new Promise((resolve) => { this.db.instance.createCollection(name, {}, (err, coll) => { @@ -42,11 +59,14 @@ export function createCollection(name) { }); } +/** + * @param {String} email + */ export function getUserByEmail(email) { return new Promise((resolve) => { let collection = this.getUserCollection(); collection.find({email: email}).toArray((err, docs) => { - resolve(docs[0]); + resolve(docs); }); }); } @@ -57,22 +77,14 @@ export function getUserCollection() { ); } +/** + * @param {Object} obj + */ export function createUser(obj) { let collection = this.getUserCollection(); - let user = { - username: obj.username, - email: obj.email, - position: obj.position, - exp: obj.exp, - stardust: obj.stardust, - pokecoins: obj.pokecoins, - avatar: obj.avatar, - team: obj.team, - contact_settings: obj.contact_settings, - tutorial_state: obj.tutorial_state - }; + let user = this.getUserData(obj); return new Promise((resolve) => { collection.insert([user], (error, result) => { @@ -82,27 +94,51 @@ export function createUser(obj) { } +/** + * @param {Object} obj + */ export function updateUser(obj) { let collection = this.getUserCollection(); - let user = { - username: obj.username, - email: obj.email, - position: obj.position, - exp: obj.exp, - stardust: obj.stardust, - pokecoins: obj.pokecoins, - avatar: obj.avatar, - team: obj.team, - contact_settings: obj.contact_settings, - tutorial_state: obj.tutorial_state - }; + let user = this.getUserData(obj); return new Promise((resolve) => { - collection.update({email: obj.email}, user, (error, result) => { + collection.update({email: user.email}, user, (error, result) => { resolve(); }); }); +} + +/** + * @param {Object} obj + * @return {Object} + */ +export function getUserData(obj) { + return ({ + username: obj.username, + email: obj.email, + exp: obj.exp, + stardust: obj.stardust, + pokecoins: obj.pokecoins, + team: obj.team, + + skin: obj.skin, + hair: obj.skin, + shirt: obj.skin, + pants: obj.skin, + hat: obj.skin, + shoes: obj.skin, + eyes: obj.skin, + gender: obj.skin, + backpack: obj.skin, + + latitude: obj.latitude, + longitude: obj.latitude, + altitude: obj.latitude, + + send_marketing_emails: false, + send_push_notifications: false + }); } \ No newline at end of file diff --git a/src/db/mysql.js b/src/db/mysql.js index 96c290d..a078d20 100644 --- a/src/db/mysql.js +++ b/src/db/mysql.js @@ -2,7 +2,7 @@ import mysql from "mysql"; import * as CFG from "../../cfg"; -export function setupMySQL() { +export function setupConnection() { let connection = mysql.createConnection({ host : CFG.SERVER_MYSQL_HOST_IP, @@ -19,8 +19,178 @@ export function setupMySQL() { return void 0; } this.db.instance = connection; - resolve(); + this.createTableIfNoExists().then(() => { + resolve(); + }); }); }); +} + +export function createTableIfNoExists() { + return new Promise((resolve) => { + this.db.instance.query(`SHOW TABLES LIKE '${CFG.SERVER_MYSQL_TABLE}';`, (e, rows, fields) => { + if (e) console.log(e); + else { + // exists + if (rows && rows.length) resolve(); + // create user table + else this.createTable(CFG.SERVER_MYSQL_TABLE).then(resolve); + } + }); + }); +} + +/** + * @param {String} name + */ +export function createTable(name) { + this.print(`Creating table ${CFG.SERVER_MYSQL_TABLE}`, 36); + return new Promise((resolve) => { + let query = ` + CREATE TABLE IF NOT EXISTS ${name} ( + id int(11) NOT NULL, + username longtext NOT NULL, + email longtext NOT NULL, + exp int(255) NOT NULL, + stardust int(255) NOT NULL, + pokecoins int(255) NOT NULL, + team int(11) NOT NULL, + latitude double NOT NULL, + longitude double NOT NULL, + altitude int(255) NOT NULL, + send_marketing_emails tinyint(1) NOT NULL, + send_push_notifications tinyint(1) NOT NULL, + skin int(11) NOT NULL, + hair int(11) NOT NULL, + shirt int(11) NOT NULL, + pants int(11) NOT NULL, + hat int(11) NOT NULL, + shoes int(11) NOT NULL, + eyes int(11) NOT NULL, + gender int(11) NOT NULL, + backpack int(11) NOT NULL + ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1; + `; + this.db.instance.query(query, (e, rows, fields) => { + if (e) console.log(e); + else resolve(); + }); + }); +} + +/** + * @param {Function} resolve + */ +export function closeConnection(resolve) { + this.db.instance.end(() => { + resolve(); + }); +} + +/** + * @param {String} email + */ +export function getUserByEmail(email) { + return new Promise((resolve) => { + this.db.instance.query(`SELECT * FROM ${CFG.SERVER_MYSQL_TABLE} WHERE email=? LIMIT 1`, [email], (e, rows, fields) => { + if (e) console.log(e); + else resolve(rows); + }); + }); +} + +/** + * @param {Object} obj + */ +export function createUser(obj) { + + let query = this.getUserQuery("INSERT INTO", ""); + let data = this.getUserQueryData(obj); + + return new Promise((resolve) => { + this.db.instance.query(query, data, resolve); + }); + +} + +/** + * @param {Object} obj + */ +export function updateUser(obj) { + + let query = this.getUserQuery("UPDATE", "WHERE email=? LIMIT 1"); + let data = this.getUserQueryData(obj); + + return new Promise((resolve) => { + this.db.instance.query(query, data, resolve); + }); + +} + +/** + * @return {String} + */ +export function getUserQuery(cmd, after) { + return (` + ${cmd} ${CFG.SERVER_MYSQL_TABLE} + SET + username=?, + email=?, + exp=?, + stardust=?, + pokecoins=?, + team=?, + latitude=?, + longitude=?, + altitude=?, + send_marketing_emails=?, + send_push_notifications=?, + skin=?, + hair=?, + shirt=?, + pants=?, + hat=?, + shoes=?, + eyes=?, + gender=?, + backpack=? + ${after} + `); +} + +/** + * @param {Object} obj + * @return {Array} + */ +export function getUserQueryData(obj) { + + return ([ + obj.username, + obj.email, + obj.exp, + obj.stardust, + obj.pokecoins, + obj.team, + // position + obj.latitude, + obj.longitude, + obj.altitude, + // contact settings + obj.send_marketing_emails, + obj.send_push_notifications, + // avatar + obj.skin, + obj.hair, + obj.shirt, + obj.pants, + obj.hat, + obj.shoes, + obj.eyes, + obj.gender, + obj.backpack, + // where + obj.email + ]); + } \ No newline at end of file diff --git a/src/index.js b/src/index.js index 18777b7..72ca72e 100644 --- a/src/index.js +++ b/src/index.js @@ -87,6 +87,7 @@ class GameServer { password: CFG.SERVER_POGO_CLIENT_PASSWORD, downloadModels: false }).then(() => { + this.print("Created asset download session"); resolve(); }); }); @@ -134,6 +135,43 @@ class GameServer { return (server); } + setupDatabaseConnection() { + + return new Promise((resolve) => { + + let name = String(CFG.SERVER_USE_DATABASE).toUpperCase(); + + switch (name) { + case "MONGO": + case "MONGODB": + inherit(GameServer, _mongo); + this.setupConnection().then(resolve); + break; + case "MYSQL": + inherit(GameServer, _mysql); + this.setupConnection().then(resolve); + break; + default: + this.print("Invalid database connection type!", 31); + return void 0; + break; + }; + + }); + + } + + shutdown() { + this.socket.close(() => { + this.print("Closed http server!", 33); + this.closeConnection(() => { + this.print("Closed database connection!", 33); + this.print("Server shutdown!", 31); + setTimeout(() => process.exit(1), 2e3); + }); + }); + } + /** * @param {String} msg * @param {Number} color @@ -155,8 +193,6 @@ inherit(GameServer, _player); inherit(GameServer, _request); inherit(GameServer, _response); inherit(GameServer, _process); -inherit(GameServer, _mongo); -inherit(GameServer, _mysql); let server = new GameServer(); diff --git a/src/packets/Responses.GetMapObjects.js b/src/packets/Responses.GetMapObjects.js index c06f0b3..567878c 100644 --- a/src/packets/Responses.GetMapObjects.js +++ b/src/packets/Responses.GetMapObjects.js @@ -76,7 +76,7 @@ export default function GetMapObjects(request) { new proto.Map.Pokemon.MapPokemon({ spawn_point_id: "87bdd289c69", encounter_id: 11810991820755313517, - pokemon_id: 19, + pokemon_id: 16, latitude: 39.19047143172622, longitude: -96.58502161502839, expiration_timestamp_ms: (new Date().getTime() + 1e6) * 1e3 @@ -86,7 +86,7 @@ export default function GetMapObjects(request) { cell.nearby_pokemons = [ new proto.Map.Pokemon.NearbyPokemon({ distance_in_meters: 200.0, - pokemon_id: 19 + pokemon_id: 16 }) ]; diff --git a/src/packets/Responses.GetPlayer.js b/src/packets/Responses.GetPlayer.js index 5b0f126..098ecc3 100644 --- a/src/packets/Responses.GetPlayer.js +++ b/src/packets/Responses.GetPlayer.js @@ -37,19 +37,22 @@ function buildPlayerData(obj) { let pokecoins = obj.pokecoins; let stardust = obj.stardust; - let avatar = obj.avatar || { - skin: 0, - hair: 2, - shirt: 1, - pants: 2, - hat: 0, - shoes: 2, - eyes: 3, - gender: proto.Enums.Gender.MALE, - backpack: 1 + let avatar = { + skin: obj.skin, + hair: obj.hair, + shirt: obj.shirt, + pants: obj.pants, + hat: obj.hat, + shoes: obj.shoes, + eyes: obj.eyes, + gender: obj.gender, + backpack: obj.backpack }; - let contact_settings = obj.contact_settings; + let contact_settings = { + send_marketing_emails: obj.send_marketing_emails, + send_push_notifications: obj.send_push_notifications + }; let tutorial_state = [ proto.Enums.TutorialState.LEGAL_SCREEN, diff --git a/src/player.js b/src/player.js index 4e0c12c..aab0ba1 100644 --- a/src/player.js +++ b/src/player.js @@ -20,37 +20,31 @@ class Player { this.uid = -1; this.email = null; - this._username = "undefined"; + this.username = "undefined"; - this.position = { - latitude: 0, - longitude: 0, - altitude: 0 - }; + this.latitude = 0; + this.longitude = 0; + this.altitude = 0; - this.contact_settings = { - send_marketing_emails: false, - send_push_notifications: false - }; + this.send_marketing_emails = false; + this.send_push_notifications = false; this.exp = 0; this.stardust = 0; this.pokecoins = 0; - this.team = proto.Enums.TeamColor.BLUE; + this.team = 0; - this.avatar = { - skin: 0, - hair: 0, - shirt: 0, - pants: 0, - hat: 0, - shoes: 0, - eyes: 0, - gender: 0, - backpack: 0 - }; + this.skin = 0; + this.hair = 0; + this.shirt = 0; + this.pants = 0; + this.hat = 0; + this.shoes = 0; + this.eyes = 0; + this.gender = 0; + this.backpack = 0; this.tutorial_state = [32, 1, 3, 4, 7]; @@ -81,13 +75,11 @@ class Player { } updateByObject(obj) { - for (let key in obj) { if (this.hasOwnProperty(key)) { this[key] = obj[key]; } }; - } /** @@ -99,9 +91,7 @@ class Player { this.latitude = data.latitude; this.longitude = data.longitude; - //this.position.altitude = data.altitude; - - //console.log(`Updated position: ${data.latitude};${data.longitude}`); + this.altitude = data.altitude; } @@ -111,17 +101,15 @@ class Player { if (!data) return void 0; - this.avatar = { - skin: data.skin, - hair: data.hair, - shirt: data.shirt, - pants: data.pants, - hat: data.hat, - shoes: data.shoes, - eyes: data.eyes, - gender: data.gender, - backpack: data.backpack - }; + this.skin = data.skin; + this.hair = data.hair; + this.shirt = data.shirt; + this.pants = data.pants; + this.hat = data.hat; + this.shoes = data.shoes; + this.eyes = data.eyes; + this.gender = data.gender; + this.backpack = data.backpack; } @@ -131,32 +119,11 @@ class Player { if (!data) return void 0; - this.contact_settings.send_marketing_emails = data.send_marketing_emails; - this.contact_settings.send_push_notifications = data.send_push_notifications; + this.send_marketing_emails = data.send_marketing_emails; + this.send_push_notifications = data.send_push_notifications; } - get username() { - return (this._username); - } - set username(name) { - this._username = name; - } - - get latitude() { - return (this.position.latitude); - } - set latitude(lat) { - this.position.latitude = lat; - } - - get longitude() { - return (this.position.longitude); - } - set longitude(lng) { - this.position.longitude = lng; - } - } /** @@ -302,16 +269,14 @@ export function removeAllPlayers() { * @param {Player} player */ export function savePlayer(player) { - if (player.authenticated) { - this.updateUser(player); - } - //this.print(`${player.remoteAddress} saved into database`, 34); + return new Promise((resolve) => { + if (player.authenticated) { + this.updateUser(player).then(resolve); + } + }); } -/** - * @param {Object} doc - */ -export function loginPlayer(doc) { +export function loginPlayer() { let buffer = null; let player = this.player; @@ -319,7 +284,7 @@ export function loginPlayer(doc) { return new Promise((resolve) => { this.getUserByEmail(player.email).then((doc) => { player.updateByObject(doc); - buffer = GetPlayer(doc).encode(); + buffer = GetPlayer(player).encode(); resolve(buffer); }); }); @@ -335,13 +300,13 @@ export function forwardPlayer() { if (player.email.length) { this.print(`${player.email.replace("@gmail.com", "")} authenticated!`, 36); } - if (doc === void 0) { - this.registerPlayer(doc).then((res) => { + if (doc === void 0 || doc && !doc.length) { + this.registerPlayer().then((res) => { resolve(res); }); } else { - this.loginPlayer(doc).then((res) => { + this.loginPlayer().then((res) => { resolve(res); }); } @@ -350,10 +315,7 @@ export function forwardPlayer() { } -/** - * @param {Object} doc - */ -export function registerPlayer(doc) { +export function registerPlayer() { let player = this.player; @@ -361,7 +323,7 @@ export function registerPlayer(doc) { this.createUser(player).then(() => { this.print(`${this.player.email.replace("@gmail.com", "")} registered!`, 36); player.tutorial_state = []; - this.loginPlayer(doc).then((res) => { + this.loginPlayer().then((res) => { resolve(res); }); }); diff --git a/src/process.js b/src/process.js index a84c7ad..cbe317b 100644 --- a/src/process.js +++ b/src/process.js @@ -9,14 +9,7 @@ export function processCommand(cmd, data) { break; // Exit the server case "/exit": - this.socket.close(() => { - this.print("Closed http server!", 33); - this.db.instance.close(() => { - this.print("Closed database connection!", 33); - this.print("Killed the server!", 31); - setTimeout(() => process.exit(1), 2e3); - }); - }); + this.shutdown(); break; case "/kick": this.kickPlayer(data[1]); diff --git a/src/response.js b/src/response.js index ae3d33a..1a53aa8 100644 --- a/src/response.js +++ b/src/response.js @@ -74,7 +74,10 @@ export function processResponse(request) { case REQUEST.GET_MAP_OBJECTS: this.player.updatePosition(request); buffer = GetMapObjects(request); - this.savePlayer(player); + this.savePlayer(player).then(() => { + resolve(buffer); + }); + return void 0; break; case REQUEST.GET_DOWNLOAD_URLS: GetDownloadUrls(request, this.generateDownloadUrlByAssetId).then((res) => { @@ -85,18 +88,27 @@ export function processResponse(request) { case REQUEST.SET_AVATAR: player.updateAvatar(request); buffer = SetAvatar(player); - this.savePlayer(player); + this.savePlayer(player).then(() => { + resolve(buffer); + }); + return void 0; break; case REQUEST.SFIDA_ACTION_LOG: buffer = SfidaActionLog(); break; case REQUEST.MARK_TUTORIAL_COMPLETE: buffer = MarkTutorialComplete(player); - this.savePlayer(player); + this.savePlayer(player).then(() => { + resolve(buffer); + }); + return void 0; break; case REQUEST.CLAIM_CODENAME: buffer = ClaimCodeName(request, player); - this.savePlayer(player); + this.savePlayer(player).then(() => { + resolve(buffer); + }); + return void 0; break; case REQUEST.LEVEL_UP_REWARDS: buffer = LevelUpRewards(); @@ -110,7 +122,10 @@ export function processResponse(request) { case REQUEST.SET_CONTACT_SETTINGS: player.updateContactSettings(request); buffer = SetContactSettings(player); - this.savePlayer(player); + this.savePlayer(player).then(() => { + resolve(buffer); + }); + return void 0; break; case REQUEST.ENCOUNTER: buffer = Encounter(request); diff --git a/src/setup.js b/src/setup.js index 384b215..173b4a0 100644 --- a/src/setup.js +++ b/src/setup.js @@ -7,10 +7,12 @@ export function setup() { this.print("Booting server..", 33); this.createAssetDownloadSession().then(() => { - this.print("Created asset download session"); this.setupDatabaseConnection().then(() => { - this.print("Database connection established"); + let dbType = String(CFG.SERVER_USE_DATABASE).toLowerCase(); + let name = dbType === "mongo" ? "MongoDB" : "MySQL"; + + this.print(`\x1b[36;1m${name}\x1b[0m\x1b[${CFG.SERVER_DEFAULT_CONSOLE_COLOR};1m connection established\x1b[0m`); if (CFG.SERVER_PORT < 1) { this.print("Invalid port!", 31); @@ -26,28 +28,4 @@ export function setup() { }); }); -} - -export function setupDatabaseConnection() { - - return new Promise((resolve) => { - - let name = String(CFG.SERVER_USE_DATABASE).toUpperCase(); - - switch (name) { - case "MONGO": - case "MONGODB": - this.setupMongo().then(resolve); - break; - case "MYSQL": - this.setupMySQL().then(resolve); - break; - default: - this.print("Invalid database connection type!", 31); - return void 0; - break; - }; - - }); - } \ No newline at end of file