mirror of
https://github.com/maierfelix/POGOserver.git
synced 2026-07-12 22:31:02 -05:00
Updates
- Added api support - Improved first run setup detection - Better db instance access - Cleaner routing
This commit is contained in:
parent
59c2bc0767
commit
c66efe50b4
1
.save
Normal file
1
.save
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"isFirstRun":false,"allowedApiHosts":["localhost"],"loginDetails":{"username":"root","password":"13377"}}
|
||||
|
|
@ -6,8 +6,8 @@ export default {
|
|||
|
||||
// show greeting
|
||||
GREET: true,
|
||||
// emit api calls
|
||||
ENABLE_API: false,
|
||||
// allow api calls
|
||||
ENABLE_API: true,
|
||||
|
||||
// Server settings
|
||||
MAX_CONNECTIONS: 64,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
"babel-cli": "^6.11.4",
|
||||
"babel-preset-es2015": "^6.13.1",
|
||||
"babel-preset-stage-0": "^6.5.0",
|
||||
"url": "^0.11.0",
|
||||
"prompt": "^1.0.0",
|
||||
"fs-extra": "^0.30.0",
|
||||
"mysql": "^2.11.1",
|
||||
"jwt-decode": "^2.1.0",
|
||||
|
|
|
|||
156
src/api.js
156
src/api.js
|
|
@ -1,44 +1,138 @@
|
|||
import fs from "fs";
|
||||
import url from "url";
|
||||
import prompt from "prompt";
|
||||
|
||||
import CFG from "../cfg";
|
||||
|
||||
export function ready(e) {
|
||||
if (e) console.log(e);
|
||||
else console.log("Ready!");
|
||||
prompt.start({
|
||||
message: " ",
|
||||
delimiter: " "
|
||||
});
|
||||
|
||||
export function processApiCall(req, res, route) {
|
||||
|
||||
let save = JSON.parse(fs.readFileSync(".save", "utf8"));
|
||||
let allowedHosts = save.allowedApiHosts;
|
||||
|
||||
let hoster = url.parse(req.headers.referer).host;
|
||||
|
||||
if (!(allowedHosts.indexOf(hoster) > -1)) {
|
||||
this.grantApiAccess(req, res, route);
|
||||
return void 0;
|
||||
}
|
||||
|
||||
let raw = req.body.toString();
|
||||
let json = null;
|
||||
|
||||
try {
|
||||
json = JSON.parse(raw);
|
||||
} catch (e) {
|
||||
this.print(e, 31);
|
||||
this.answerApiCall(res, "");
|
||||
return void 0;
|
||||
}
|
||||
|
||||
if (this.isApiCall(json)) {
|
||||
json.host = hoster;
|
||||
if (json.action === "login") {
|
||||
let result = this["api_login"](json);
|
||||
this.answerApiCall(res, JSON.stringify(result));
|
||||
}
|
||||
else {
|
||||
if (this.apiClients[hoster]) {
|
||||
let result = this["api_" + json.action](json);
|
||||
this.answerApiCall(res, JSON.stringify(result));
|
||||
}
|
||||
else {
|
||||
this.print(`${hoster} isnt logged in! Kicking..`, 31);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (json.action === "init") {
|
||||
this.answerApiCall(res, JSON.stringify({ success: true }));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} msg
|
||||
* @param {Number} color
|
||||
* @param {Boolean} nl
|
||||
*/
|
||||
export function print(msg, color, newline) {
|
||||
color = Number.isInteger(color) ? color : CFG.DEFAULT_CONSOLE_COLOR;
|
||||
process.stdout.write(`[Console] \x1b[${color};1m${msg}\x1b[0m${newline === void 0 ? "\n" : ""}`);
|
||||
export function grantApiAccess(req, res, route) {
|
||||
|
||||
let save = JSON.parse(fs.readFileSync(".save", "utf8"));
|
||||
|
||||
let hoster = url.parse(req.headers.referer).host;
|
||||
|
||||
let msg = `[Console] \x1b[33mGrant API access to ${hoster}?\x1b[0m`;
|
||||
|
||||
prompt.get([{ name: "grant", required: true, description: msg }], (e, result) => {
|
||||
if (result.grant === "y" || result.grant === "yes") {
|
||||
save.allowedApiHosts.push(hoster);
|
||||
fs.writeFileSync(".save", JSON.stringify(save), "utf8");
|
||||
this.print(`Successfully added ${hoster} to allowed API hosts!`);
|
||||
this.processApiCall(req, res, route);
|
||||
}
|
||||
else {
|
||||
this.print(`Denied API access for ${hoster}`, 31);
|
||||
this.answerApiCall(res, "");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Player} player
|
||||
*/
|
||||
export function registerPlayer(player) {
|
||||
console.log(player.username + " registered!");
|
||||
export function answerApiCall(res, data) {
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE");
|
||||
res.setHeader("Access-Control-Allow-Headers", "X-Requested-With,content-type");
|
||||
res.setHeader("Access-Control-Allow-Credentials", true);
|
||||
res.end(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Player} player
|
||||
*/
|
||||
export function loginPlayer(player) {
|
||||
console.log(player.username + " logged in!");
|
||||
export function api_login(data) {
|
||||
|
||||
if (typeof data !== "object") return void 0;
|
||||
|
||||
let save = JSON.parse(fs.readFileSync(".save", "utf8"));
|
||||
|
||||
let success = false;
|
||||
|
||||
let username = save.loginDetails.username;
|
||||
let password = save.loginDetails.password;
|
||||
|
||||
if (
|
||||
username === data.username &&
|
||||
password === data.password
|
||||
) {
|
||||
success = true;
|
||||
if (!this.apiClients[data.host]) {
|
||||
this.print(`API access for ${data.host} granted!`);
|
||||
}
|
||||
this.print(`${data.host} logged in!`, 36);
|
||||
this.apiClients[data.host] = {
|
||||
timestamp: +new Date()
|
||||
};
|
||||
}
|
||||
return ({
|
||||
success: success
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Player} player
|
||||
*/
|
||||
export function killPlayer(player) {
|
||||
console.log(player.username + " killed!");
|
||||
export function api_getConnectedPlayers() {
|
||||
return ({
|
||||
connected_players: this.world.players.length
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Player} player
|
||||
*/
|
||||
export function updatePlayerAvatar(player) {
|
||||
console.log("Updated avatar of " + player.username + "!");
|
||||
export function api_getServerVersion() {
|
||||
return ({
|
||||
version: CFG.VERSION
|
||||
});
|
||||
}
|
||||
|
||||
export function api_spawnPkmnToPlayer(data) {
|
||||
let name = String(data.player);
|
||||
let pkmn = String(data.pkmn).toUpperCase();
|
||||
this.print(`Spawned 1x ${pkmn}'s to ${name}!`);
|
||||
return ({
|
||||
success: true
|
||||
});
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ import CFG from "../../cfg";
|
|||
|
||||
export function createTableIfNotExists(name) {
|
||||
return new Promise((resolve) => {
|
||||
this.db.instance.query(`SHOW TABLES LIKE '${name}';`, (e, rows, fields) => {
|
||||
this.db.query(`SHOW TABLES LIKE '${name}';`, (e, rows, fields) => {
|
||||
if (e) console.log(e);
|
||||
else {
|
||||
// exists
|
||||
|
|
@ -39,7 +39,7 @@ export function createTable(name) {
|
|||
`;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.db.instance.query(query, (e, rows) => {
|
||||
this.db.query(query, (e, rows) => {
|
||||
if (e) console.log(e);
|
||||
else resolve();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import CFG from "../../cfg";
|
|||
*/
|
||||
export function getQueryByColumnFromTable(column, value, table) {
|
||||
return new Promise((resolve) => {
|
||||
this.db.instance.query(`SELECT * FROM ${table} WHERE ${column}=?`, [value], (e, rows) => {
|
||||
this.db.query(`SELECT * FROM ${table} WHERE ${column}=?`, [value], (e, rows) => {
|
||||
if (e) console.log(e);
|
||||
if (rows && rows.length) resolve(rows);
|
||||
else resolve(void 0);
|
||||
|
|
@ -22,7 +22,7 @@ export function getQueryByColumnFromTable(column, value, table) {
|
|||
*/
|
||||
export function deleteQueryByColumnFromTable(column, value, table) {
|
||||
return new Promise((resolve) => {
|
||||
this.db.instance.query(`DELETE FROM ${table} WHERE ${column}=?`, [value], (e, rows) => {
|
||||
this.db.query(`DELETE FROM ${table} WHERE ${column}=?`, [value], (e, rows) => {
|
||||
if (e) console.log(e);
|
||||
else resolve(void 0);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export function setupDatabaseConnection() {
|
|||
this.retry("Retrying again in ", () => this.setupDatabaseConnection().then(resolve), 5);
|
||||
return void 0;
|
||||
}
|
||||
this.db.instance = connection;
|
||||
this.db = connection;
|
||||
this.createTableIfNotExists(CFG.MYSQL_USERS_TABLE).then(() => {
|
||||
this.createTableIfNotExists(CFG.MYSQL_OWNED_PKMN_TABLE).then(() => {
|
||||
this.print(`\x1b[36;1mMySQL\x1b[0m\x1b[32;1m connection established\x1b[0m`);
|
||||
|
|
@ -39,7 +39,7 @@ export function setupDatabaseConnection() {
|
|||
* @param {Function} resolve
|
||||
*/
|
||||
export function closeConnection(resolve) {
|
||||
this.db.instance.end(() => {
|
||||
this.db.end(() => {
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
|
@ -18,9 +18,7 @@ export function createHTTPServer() {
|
|||
req.on("end", () => {
|
||||
let buffer = Buffer.concat(chunks);
|
||||
req.body = buffer;
|
||||
this.world.getPlayerByRequest(req, res).then((player) => {
|
||||
this.routeRequest(player, req, res);
|
||||
});
|
||||
this.routeRequest(req, res);
|
||||
});
|
||||
});
|
||||
server.listen(CFG.PORT);
|
||||
|
|
|
|||
43
src/index.js
43
src/index.js
|
|
@ -1,6 +1,5 @@
|
|||
import fs from "fs";
|
||||
import os from "os";
|
||||
import EventEmitter from "events";
|
||||
import POGOProtos from "pokemongo-protobuf";
|
||||
|
||||
import {
|
||||
|
|
@ -30,23 +29,20 @@ const greetMessage = fs.readFileSync(".greet", "utf8");
|
|||
/**
|
||||
* @class GameServer
|
||||
*/
|
||||
export default class GameServer extends EventEmitter {
|
||||
export default class GameServer {
|
||||
|
||||
/** @constructor */
|
||||
constructor() {
|
||||
|
||||
super(null);
|
||||
|
||||
this.STATES = {
|
||||
PAUSE: false,
|
||||
DEBUG: false,
|
||||
CRASH: false
|
||||
};
|
||||
|
||||
this.db = {
|
||||
instance: null,
|
||||
collections: {}
|
||||
};
|
||||
this.db = null;
|
||||
|
||||
this.apiClients = {};
|
||||
|
||||
this.assets = {};
|
||||
this.master = null;
|
||||
|
|
@ -61,8 +57,6 @@ export default class GameServer extends EventEmitter {
|
|||
this.timeoutTick = 0;
|
||||
this.passedTicks = 0;
|
||||
|
||||
this.initAPI();
|
||||
|
||||
if (CFG.GREET) this.greet();
|
||||
|
||||
this.print(`Booting Server v${require("../package.json").version}-dev`, 33);
|
||||
|
|
@ -73,25 +67,25 @@ export default class GameServer extends EventEmitter {
|
|||
|
||||
}
|
||||
|
||||
initAPI() {
|
||||
if (CFG.ENABLE_API) {
|
||||
for (let key in _api) {
|
||||
this.on(key, _api[key]);
|
||||
};
|
||||
}
|
||||
// make sure we still have our print fn
|
||||
else {
|
||||
this.on("print", _api["print"]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} msg
|
||||
* @param {Number} color
|
||||
* @param {Boolean} nl
|
||||
*/
|
||||
print(msg, color, nl) {
|
||||
this.emit("print", msg, color, nl);
|
||||
print(msg, color, newline) {
|
||||
color = Number.isInteger(color) ? color : CFG.DEFAULT_CONSOLE_COLOR;
|
||||
process.stdout.write(`[Console] \x1b[${color};1m${msg}\x1b[0m${newline === void 0 ? "\n" : ""}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} obj
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isApiCall(call) {
|
||||
let action = String(call.action);
|
||||
return (
|
||||
"api_" + action in _api
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -163,6 +157,7 @@ export default class GameServer extends EventEmitter {
|
|||
|
||||
}
|
||||
|
||||
inherit(GameServer, _api);
|
||||
inherit(GameServer, _dump);
|
||||
inherit(GameServer, _http);
|
||||
inherit(GameServer, _setup);
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ export default class Player extends MapObject {
|
|||
this.response = obj.response;
|
||||
|
||||
this.authenticated = 0;
|
||||
|
||||
/*
|
||||
this.bag = new Bag(this);
|
||||
this.info = new Info(this);
|
||||
this.pary = new Party(this);
|
||||
this.avatar = new Avatar(this);
|
||||
this.pokedex = new Pokedex(this);
|
||||
this.tutorial = new Tutorial(this);
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -8,7 +8,11 @@ import CFG from "../../../cfg";
|
|||
export default class World {
|
||||
|
||||
/** @constructor */
|
||||
constructor() {
|
||||
constructor(instance) {
|
||||
|
||||
this.instance = instance;
|
||||
|
||||
this.db = this.instance.db;
|
||||
|
||||
this.players = [];
|
||||
|
||||
|
|
@ -31,16 +35,14 @@ export default class World {
|
|||
|
||||
let player = null;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
if (this.playerAlreadyConnected(req)) {
|
||||
player = this.getPlayerByIP(req.headers.host);
|
||||
resolve(player);
|
||||
}
|
||||
else {
|
||||
this.addPlayer(req, res);
|
||||
resolve(player);
|
||||
}
|
||||
});
|
||||
if (this.playerAlreadyConnected(req)) {
|
||||
player = this.getPlayerByIP(req.headers.host);
|
||||
return (player);
|
||||
}
|
||||
else {
|
||||
this.addPlayer(req, res);
|
||||
return (player);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@ import POGOProtos from "pokemongo-protobuf";
|
|||
import CFG from "../cfg";
|
||||
|
||||
/**
|
||||
* @param {Player} player
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
export function routeRequest(player, req, res) {
|
||||
export function routeRequest(req, res) {
|
||||
|
||||
let parsed = url.parse(req.url).pathname;
|
||||
let route = parsed.split("/");
|
||||
|
|
@ -19,31 +18,60 @@ export function routeRequest(player, req, res) {
|
|||
switch (route[1]) {
|
||||
case "plfe":
|
||||
case "custom":
|
||||
if (route[2] === "rpc") this.onRequest(player, req);
|
||||
this.processRpcRequest(req, res, route);
|
||||
break;
|
||||
case "model":
|
||||
// make sure no random dudes can access download
|
||||
if (!player.authenticated) return void 0;
|
||||
let name = route[2];
|
||||
if (name && name.length > 1) {
|
||||
let folder = player.isAndroid ? "android/" : "ios/";
|
||||
fs.readFile("data/" + folder + name, (error, data) => {
|
||||
if (error) {
|
||||
this.print(`Error file resolving model ${name}:` + error, 31);
|
||||
return void 0;
|
||||
}
|
||||
this.print(`Sent ${name} to ${player.email}`, 36);
|
||||
res.end(data);
|
||||
});
|
||||
this.processModelRequest(req, res, route);
|
||||
break;
|
||||
case "api":
|
||||
if (!CFG.ENABLE_API) return void 0;
|
||||
if (req.method === "POST") {
|
||||
this.processApiCall(req, res, route);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log(`Unknown request url: https://${req.headers.host}${req.url}`);
|
||||
console.log(`Unknown request url: https://${host}${req.url}`);
|
||||
break;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Array} route
|
||||
*/
|
||||
export function processRpcRequest(req, res, route) {
|
||||
let player = this.world.getPlayerByRequest(req, res);
|
||||
if (route[2] === "rpc") this.onRequest(player, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {Array} route
|
||||
*/
|
||||
export function processModelRequest(req, res, route) {
|
||||
|
||||
let player = this.world.getPlayerByRequest(req, res);
|
||||
|
||||
// make sure no random dudes can access download
|
||||
if (!player.authenticated) return void 0;
|
||||
let name = route[2];
|
||||
if (name && name.length > 1) {
|
||||
let folder = player.isAndroid ? "android/" : "ios/";
|
||||
fs.readFile("data/" + folder + name, (error, data) => {
|
||||
if (error) {
|
||||
this.print(`Error file resolving model ${name}:` + error, 31);
|
||||
return void 0;
|
||||
}
|
||||
this.print(`Sent ${name} to ${player.email}`, 36);
|
||||
res.end(data);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Player} player
|
||||
* @param {Request} req
|
||||
|
|
|
|||
10
src/setup.js
10
src/setup.js
|
|
@ -16,12 +16,14 @@ import {
|
|||
|
||||
export function setup() {
|
||||
|
||||
let isFirstRun = !this.fileExists(CFG.DUMP_ASSET_PATH);
|
||||
let save = JSON.parse(fs.readFileSync(".save", "utf8"));
|
||||
|
||||
if (isFirstRun) {
|
||||
this.print("Required assets are missing! Preparing dump session..", 31);
|
||||
if (save.isFirstRun) {
|
||||
this.print("Required assets are missing! Preparing dump session..", 33);
|
||||
setTimeout(() => {
|
||||
this.onFirstRun(() => {
|
||||
save.isFirstRun = false;
|
||||
fs.writeFileSync(".save", JSON.stringify(save), "utf8");
|
||||
this.setup();
|
||||
});
|
||||
}, 1e3);
|
||||
|
|
@ -46,13 +48,11 @@ export function setup() {
|
|||
setTimeout(this::this.cycle, 1);
|
||||
let localIPv4 = this.getLocalIPv4();
|
||||
this.print(`Server listening at ${localIPv4}:${CFG.PORT}`, 33);
|
||||
this.emit("ready", void 0);
|
||||
});
|
||||
|
||||
}).catch((e) => {
|
||||
//fse.removeSync(CFG.DUMP_ASSET_PATH);
|
||||
this.print("Error: " + e + " was not found!", 31);
|
||||
this.emit("ready", e);
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user