diff --git a/.greet b/.greet new file mode 100644 index 0000000..e80ceec --- /dev/null +++ b/.greet @@ -0,0 +1,6 @@ + ______ _____ _____ _____ + | ___ \ _ | __ \ _ | + | |_/ / | | | | \/ | | | ___ ___ _ ____ _____ _ __ + | __/| | | | | __| | | |/ __|/ _ \ '__\ \ / / _ \ '__| + | | \ \_/ / |_\ \ \_/ /\__ \ __/ | \ V / __/ | + \_| \___/ \____/\___/ |___/\___|_| \_/ \___|_| diff --git a/asset_digest b/asset_digest index 27fbb7f..57f3afa 100644 Binary files a/asset_digest and b/asset_digest differ diff --git a/cfg.js b/cfg.js index b2212d1..51322f7 100644 --- a/cfg.js +++ b/cfg.js @@ -4,8 +4,10 @@ export const SERVER_GAME_MODE = 0; export const SERVER_TICK_INTERVAL = 1; // better dont change export const SERVER_SAVE_INTERVAL = 120000; // all 120s export const SERVER_MAX_CONNECTIONS = 64; -export const SERVER_PLAYER_CONNECTION_TIMEOUT = 30000; // 1min +export const SERVER_PLAYER_CONNECTION_TIMEOUT = 60000; // 1min export const SERVER_DEFAULT_CONSOLE_COLOR = 32; -export const ASSET_DIGEST_PATH = "asset_digest"; \ No newline at end of file +export const ASSET_DIGEST_PATH = "asset_digest"; + +export const MINIMUM_CLIENT_VERSION = "0.31.0"; \ No newline at end of file diff --git a/src/cycle.js b/src/cycle.js index d62487b..b620613 100644 --- a/src/cycle.js +++ b/src/cycle.js @@ -65,8 +65,9 @@ export function playerTimeoutTick() { for (; ii < length; ++ii) { client = this.clients[ii]; if (this.time - client.timeout >= maxTimeout) { - this.print(`${client.remoteAddress} timed out!`, 36); - this.killPlayer(client); + this.print(`${client.remoteAddress} timed out`, 34); + this.savePlayer(client); + this.removePlayer(client); } }; diff --git a/src/index.js b/src/index.js index 5535b1a..cd32369 100644 --- a/src/index.js +++ b/src/index.js @@ -14,6 +14,8 @@ import * as _request from "./request"; import * as _process from "./process"; import * as _database from "./database"; +const greetMessage = fs.readFileSync(".greet", "utf8"); + /** * @class GameServer */ @@ -28,10 +30,11 @@ class GameServer { CRASH: false }; - this.paused = false; - this.proto = null; this.socket = null; + this.player = null; + this.request = null; + this.response = null; this.cycleInstance = null; // Timer things @@ -44,6 +47,7 @@ class GameServer { this.clients = []; + this.greet(); this.setup(); } @@ -64,10 +68,13 @@ class GameServer { } + /** + * @return {HTTP} + */ createHTTPServer() { let server = http.createServer((req, res) => { + this.response = res; if (!this.clientAlreadyConnected(req)) { - this.print(`${req.connection.remoteAddress} connected!`, 36); this.addPlayer(req.connection); } let chunks = []; @@ -75,18 +82,13 @@ class GameServer { chunks.push(chunk); }); req.on("end", () => { - // Reset player timeout - let player = this.getPlayerByRequest(req); - if (player !== null) player.timeout = this.time; - // Data let buffer = Buffer.concat(chunks); req.body = buffer; + this.request = req; this.onRequest(req, res); }); }); - server.listen(CFG.SERVER_PORT, CFG.SERVER_HOST_IP, () => { - - }); + server.listen(CFG.SERVER_PORT); return (server); } @@ -99,6 +101,10 @@ class GameServer { console.log(`\x1b[${color};1m${msg}\x1b[0m`); } + greet() { + console.log(greetMessage); + } + } inherit(GameServer, _setup); diff --git a/src/packets/Envelopes.AuthTicket.js b/src/packets/Envelopes.AuthTicket.js new file mode 100644 index 0000000..91ac460 --- /dev/null +++ b/src/packets/Envelopes.AuthTicket.js @@ -0,0 +1,14 @@ +import proto from "../proto"; + +/** + * @return {Object} + */ +export default function AuthTicket() { + + return ( + new proto.Networking.Envelopes.AuthTicket({ + expire_timestamp_ms: 9999999999999, + }) + ); + +} diff --git a/src/packets/Envelopes.ResponseEnvelope.Auth.js b/src/packets/Envelopes.ResponseEnvelope.Auth.js new file mode 100644 index 0000000..61d1a82 --- /dev/null +++ b/src/packets/Envelopes.ResponseEnvelope.Auth.js @@ -0,0 +1,22 @@ +import proto from "../proto"; + +/** + * @param {Object} obj + * @return {Object} + */ +export default function ResponseEnvelope(obj) { + + return ( + new proto.Networking.Envelopes.ResponseEnvelope({ + status_code: 53, + request_id: obj.id, + api_url: "pgorelease.nianticlabs.com/custom", + auth_ticket: new proto.Networking.Envelopes.AuthTicket({ + start: new Buffer(""), + expire_timestamp_ms: 9999999999999, + end: new Buffer("") + }) + }).encode().toBuffer() + ); + +} \ No newline at end of file diff --git a/src/packets/Envelopes.ResponseEnvelope.js b/src/packets/Envelopes.ResponseEnvelope.js index 7a92dcb..5e05da7 100644 --- a/src/packets/Envelopes.ResponseEnvelope.js +++ b/src/packets/Envelopes.ResponseEnvelope.js @@ -16,8 +16,8 @@ export default function ResponseEnvelope(obj) { }) }), request_id: obj.id, - returns: obj.res - }) + returns: obj.response + }).encode().toBuffer() ); } \ No newline at end of file diff --git a/src/packets/Responses.CheckAwardedBadges.js b/src/packets/Responses.CheckAwardedBadges.js new file mode 100644 index 0000000..61c0bf8 --- /dev/null +++ b/src/packets/Responses.CheckAwardedBadges.js @@ -0,0 +1,17 @@ +import * as CFG from "../../cfg"; + +import proto from "../proto"; + +/** + * @param {Object} obj + * @return {Object} + */ +export default function CheckAwardedBadges(obj) { + + return ( + new proto.Networking.Responses.CheckAwardedBadgesResponse({ + success: true + }).encode() + ); + +} \ No newline at end of file diff --git a/src/packets/Responses.DownloadRemoteConfigVersion.js b/src/packets/Responses.DownloadRemoteConfigVersion.js index 30801d9..8551461 100644 --- a/src/packets/Responses.DownloadRemoteConfigVersion.js +++ b/src/packets/Responses.DownloadRemoteConfigVersion.js @@ -7,8 +7,10 @@ import proto from "../proto"; export default function DownloadRemoteConfigVersion(obj) { return ( - new proto.Networking.Responses.DownloadSettingsResponse({ - hash: "54b359c97e46900f87211ef6e6dd0b7f2a3ea1f5" + new proto.Networking.Responses.DownloadRemoteConfigVersionResponse({ + result: 1, + item_templates_timestamp_ms: 1468540960537, + asset_digest_timestamp_ms: 1467338276561000 }).encode() ); diff --git a/src/packets/Responses.DownloadSettings.js b/src/packets/Responses.DownloadSettings.js index 6fe2d62..f8ea62f 100644 --- a/src/packets/Responses.DownloadSettings.js +++ b/src/packets/Responses.DownloadSettings.js @@ -1,5 +1,7 @@ import proto from "../proto"; +import * as CFG from "../../cfg"; + /** * @param {Object} obj * @return {Object} @@ -8,7 +10,33 @@ export default function DownloadSettings(obj) { return ( new proto.Networking.Responses.DownloadSettingsResponse({ - hash: "b1f2bf509a025b7cd76e1c484e2a24411c50f0612" + hash: "54b359c97e46900f87211ef6e6dd0b7f2a3ea1f5", + settings: new proto.Settings.GlobalSettings({ + fort_settings: new proto.Settings.FortSettings({ + interaction_range_meters: 40, + max_total_deployed_pokemon: 10, + max_player_deployed_pokemon: 1, + deploy_stamina_multiplier: 500, + far_interaction_range_meters: 1000 + }), + map_settings: new proto.Settings.MapSettings({ + pokemon_visible_range: 70, + poke_nav_range_meters: 201, + encounter_range_meters: 50, + get_map_objects_min_refresh_seconds: 5, + get_map_objects_max_refresh_seconds: 30, + get_map_objects_min_distance_meters: 10, + google_maps_api_key: "AIzaSyDF9rkP8lhcddBtvH9gVFzjnNo13WtmJIM" + }), + inventory_settings: new proto.Settings.InventorySettings({ + max_pokemon: 1000, + max_bag_items: 1000, + base_pokemon: 250, + base_bag_items: 350, + base_eggs: 1000 + }), + minimum_client_version: CFG.MINIMUM_CLIENT_VERSION + }) }).encode() ); diff --git a/src/packets/Responses.GetAssetDigest.js b/src/packets/Responses.GetAssetDigest.js index 7a685de..2e74ddf 100644 --- a/src/packets/Responses.GetAssetDigest.js +++ b/src/packets/Responses.GetAssetDigest.js @@ -1,6 +1,9 @@ +import fs from "fs"; +import proto from "../proto"; + import * as CFG from "../../cfg"; -import proto from "../proto"; +let asset = fs.readFileSync(CFG.ASSET_DIGEST_PATH); /** * @param {Object} obj @@ -8,8 +11,6 @@ import proto from "../proto"; */ export default function GetAssetDigest(obj) { - return ( - fs.readFileSync("../../" + CFG.ASSET_DIGEST_PATH) - ); + return (asset); } \ No newline at end of file diff --git a/src/packets/Responses.GetPlayer.js b/src/packets/Responses.GetPlayer.js index f24aa17..1689022 100644 --- a/src/packets/Responses.GetPlayer.js +++ b/src/packets/Responses.GetPlayer.js @@ -6,22 +6,25 @@ import proto from "../proto"; */ function getPlayerDataPacket(obj) { - return new proto.Data.PlayerData({ - creation_timestamp_ms: 1467936859925, - username: obj.username, - team: obj.team, - tutorial_state: obj.tutorial_state, - avatar: new proto.Data.Player.PlayerAvatar(obj.avatar), - max_pokemon_storage: 250, - max_item_storage: 350, - daily_bonus: new proto.Data.Player.DailyBonus({ - next_defender_bonus_collect_timestamp_ms: 1470174535972 - }), - contact_settings: new proto.Data.Player.ContactSettings({ - send_marketing_emails: true - }), - currencies: obj.currencies - }); + return ( + new proto.Data.PlayerData({ + creation_timestamp_ms: 1467936859925, + username: obj.username, + team: obj.team, + tutorial_state: obj.tutorial_state, + avatar: new proto.Data.Player.PlayerAvatar(obj.avatar), + max_pokemon_storage: 250, + max_item_storage: 350, + daily_bonus: new proto.Data.Player.DailyBonus({ + next_defender_bonus_collect_timestamp_ms: 1470174535972 + }), + // equipped_badge: new proto.Data.Player.EquippedBadge({}), + contact_settings: new proto.Data.Player.ContactSettings({ + send_marketing_emails: true + }), + currencies: obj.currencies + }) + ); } diff --git a/src/packets/Responses.GetPlayerProfile.js b/src/packets/Responses.GetPlayerProfile.js new file mode 100644 index 0000000..56d7a7f --- /dev/null +++ b/src/packets/Responses.GetPlayerProfile.js @@ -0,0 +1,25 @@ +import proto from "../proto"; + +/** + * @param {Object} obj + * @return {Object} + */ +export default function GetPlayerProfile(obj) { + + return ( + new proto.Networking.Responses.GetPlayerProfileResponse({ + result: proto.Networking.Responses.GetPlayerProfileResponse.Result.SUCCESS, + start_time: new Date().getTime() * 1000, + badges: [ + new proto.Data.PlayerBadge({ + badge_type: proto.Enums.BadgeType.BADGE_PIKACHU, + rank: 1, + start_value: 0, + end_value: 2000, + current_value: 1337 + }) + ] + }).encode() + ); + +} \ No newline at end of file diff --git a/src/packets/Responses.ItemTemplates.js b/src/packets/Responses.ItemTemplates.js new file mode 100644 index 0000000..3309c15 --- /dev/null +++ b/src/packets/Responses.ItemTemplates.js @@ -0,0 +1,141 @@ +import * as CFG from "../../cfg"; + +import proto from "../proto"; + +/** + * @param {Object} obj + * @return {Object} + */ +export default function ItemTemplates(obj) { + + return ( + new proto.Networking.Responses.DownloadItemTemplatesResponse({ + success: true, + item_templates: new proto.Networking.Responses.DownloadItemTemplatesResponse.ItemTemplate({ + pokemon_settings: null, + // unused but saved here for later use + item_settings: new proto.Settings.Master.ItemSettings({ + "item_id": 702, + "item_type": 6, + "category": 2, + "drop_freq": 0, + "drop_trainer_level": 0, + "pokeball": null, + "potion": null, + "revive": null, + "battle": null, + "food": null, + "inventory_upgrade": null, + "xp_boost": null, + "incense": null, + "egg_incubator": null, + "fort_modifier": null + }), + // unused but saved here for later use + move_settings: new proto.Settings.Master.MoveSettings({ + "movement_id": 13, + "animation_id": 5, + "pokemon_type": 1, + "power": 25, + "accuracy_chance": 1, + "critical_chance": 0.05000000074505806, + "heal_scalar": 0, + "stamina_loss_scalar": 0.05999999865889549, + "trainer_level_min": 1, + "trainer_level_max": 100, + "vfx_name": "wrap", + "duration_ms": 4000, + "damage_window_start_ms": 2800, + "damage_window_end_ms": 3400, + "energy_delta": -20 + }), + move_sequence_settings: new proto.Settings.Master.MoveSequenceSettings({ + "sequence": ["anim attacker atk-move", "f2fvfx attacker acid_fast", "sfx attacker 051-0_acid", "wait 0.15", "vfx defender acid_fast_hit", "anim defender damageS01", "wait 0.35", "sys ui-sync", "sys complete"] + }), + type_effective: new proto.Settings.Master.TypeEffectiveSettings({ + "attack_scalar": [1, 0.800000011920929, 0.800000011920929, 0.800000011920929, 1, 1, 1, 0.800000011920929, 0.800000011920929, 0.800000011920929, 1, 1.25, 1, 1.25, 1, 1, 1.25, 0.800000011920929], + "attack_type": 7 + }), + badge_settings: new proto.Settings.Master.BadgeSettings({ + "badge_type": 13, + "badge_rank": 4, + "targets": [10, 100, 1000] + }), + // unused but saved here for later use + camera: new proto.Settings.Master.CameraSettings({ + "next_camera": "", + "interpolation": [1], + "target_type": [12], + "ease_in_speed": [0], + "east_out_speed": [0], + "duration_seconds": [5], + "wait_seconds": [0], + "transition_seconds": [0.5], + "angle_degree": [-20], + "angle_offset_degree": [0], + "pitch_degree": [20], + "pitch_offset_degree": [0], + "roll_degree": [0], + "distance_meters": [4], + "height_percent": [0], + "vert_ctr_ratio": [1] + }), + player_level: new proto.Settings.Master.PlayerLevelSettings({ + "rank_num": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "required_experience": [0, 1000, 3000, 6000, 10000, 15000, 21000, 28000, 36000, 45000, 55000, 65000, 75000, 85000, 100000, 120000, 140000, 160000, 185000, 210000, 260000, 335000, 435000, 560000, 710000, 900000, 1100000, 1350000, 1650000, 2000000, 2500000, 3000000, 3750000, 4750000, 6000000, 7500000, 9500000, 12000000, 15000000, 20000000], + "cp_multiplier": [0.09399999678134918, 0.16639786958694458, 0.21573247015476227, 0.2557200491428375, 0.29024988412857056, 0.3210875988006592, 0.3492126762866974, 0.37523558735847473, 0.39956727623939514, 0.42250001430511475, 0.443107545375824, 0.4627983868122101, 0.48168495297431946, 0.49985843896865845, 0.517393946647644, 0.5343543291091919, 0.5507926940917969, 0.5667545199394226, 0.5822789072990417, 0.5974000096321106, 0.6121572852134705, 0.6265671253204346, 0.6406529545783997, 0.6544356346130371, 0.667934000492096, 0.6811649203300476, 0.6941436529159546, 0.7068842053413391, 0.719399094581604, 0.7317000031471252, 0.7377694845199585, 0.7437894344329834, 0.7497610449790955, 0.7556855082511902, 0.7615638375282288, 0.7673971652984619, 0.7731865048408508, 0.7789327502250671, 0.7846369743347168, 0.7903000116348267], + "max_egg_player_level": 20, + "max_encounter_player_level": 30 + }), + gym_level: new proto.Settings.Master.GymLevelSettings({ + "required_experience": [0, 2000, 4000, 8000, 12000, 16000, 20000, 30000, 40000, 50000], + "leader_slots": [1, 1, 1, 2, 2, 2, 3, 3, 3, 4], + "trainer_slots": [0, 1, 2, 2, 3, 4, 4, 5, 6, 6], + "search_roll_bonus": [] + }), + battle_settings: new proto.Settings.Master.GymBattleSettings({ + "energy_per_sec": 0, + "dodge_energy_cost": 0, + "retarget_seconds": 0.5, + "enemy_attack_interval": 1.5, + "attack_server_interval": 5, + "round_duration_seconds": 99, + "bonus_time_per_ally_seconds": 10, + "maximum_attackers_per_battle": 20, + "same_type_attack_bonus_multiplier": 1.25, + "maximum_energy": 100, + "energy_delta_per_health_lost": 0.5, + "dodge_duration_ms": 500, + "minimum_player_level": 5, + "swap_duration_ms": 1000 + }), + encounter_settings: new proto.Settings.Master.EncounterSettings({ + "spin_bonus_threshold": 0.5, + "excellent_throw_threshold": 1.7000000476837158, + "great_throw_threshold": 1.2999999523162842, + "nice_throw_threshold": 1, + "milestone_threshold": 100 + }), + iap_item_display: null, // seems like useless?? + iap_settings: new proto.Settings.Master.IapSettings({ + "daily_bonus_coins": 0, + "daily_defender_bonus_per_pokemon": [500, 10], + "daily_defender_bonus_max_defenders": 10, + "daily_defender_bonus_currency": ["STARDUST", "POKECOIN"], + "min_time_between_claims_ms": 0, + "daily_bonus_enabled": false, + "daily_defender_bonus_enabled": true + }), + pokemon_upgrades: new proto.Settings.Master.PokemonUpgradeSettings({ + "upgrades_per_level": 2, + "allowed_levels_above_player": 2, + "candy_cost": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 15, 15], + "stardust_cost": [200, 200, 400, 400, 600, 600, 800, 800, 1000, 1000, 1300, 1300, 1600, 1600, 1900, 1900, 2200, 2200, 2500, 2500, 3000, 3000, 3500, 3500, 4000, 4000, 4500, 4500, 5000, 5000, 6000, 6000, 7000, 7000, 8000, 8000, 9000, 9000, 10000, 10000] + }), + equipped_badges: null // seems like unused + }), + timestamp_ms: 1468540960537 + }).encode() + ); + +} \ No newline at end of file diff --git a/src/packets/index.js b/src/packets/index.js index b615cba..0aa276e 100644 --- a/src/packets/index.js +++ b/src/packets/index.js @@ -5,6 +5,11 @@ export GetAssetDigest from "./Responses.GetAssetDigest"; export GetHatchedEggs from "./Responses.GetHatchedEggs"; export GetInventory from "./Responses.GetInventory"; export GetPlayer from "./Responses.GetPlayer"; +export GetPlayerProfile from "./Responses.GetPlayerProfile"; + +export ItemTemplates from "./Responses.ItemTemplates"; +export CheckAwardedBadges from "./Responses.CheckAwardedBadges"; export AuthTicket from "./Envelopes.AuthTicket"; -export ResponseEnvelope from "./Envelopes.ResponseEnvelope"; \ No newline at end of file +export ResponseEnvelope from "./Envelopes.ResponseEnvelope"; +export ResponseEnvelopeAuth from "./Envelopes.ResponseEnvelope.Auth"; \ No newline at end of file diff --git a/src/player.js b/src/player.js index 07fb5ad..16ce3cf 100644 --- a/src/player.js +++ b/src/player.js @@ -1,18 +1,98 @@ +import proto from "./proto"; + import * as CFG from "../cfg"; -export function killPlayer(player) { +import { + getHashCodeFrom, + decodeRequestEnvelope +} from "./utils"; - let index = this.getPlayerIndex(player); +/** + * @class Player + */ +class Player { + + /** @constructor */ + constructor(obj) { + + this.uid = -1; + + this.name = null; + + this.email = null; + + this.position = { + latitude: 0, + longitude: 0, + altitude: 0 + }; + + this.exp = 0; + + this.stardust = 0; + this.pokecoins = 0; + + this.avatar = null; + this.badges = null; + this.pokedex = null; + this.inventory = null; + + this.response = obj.response; + this.connection = obj.connection; + + this.timeout = obj.timeout; + + this.remotePort = obj.remotePort; + this.remoteAddress = obj.remoteAddress; + + this.currentEncounter = null; + + this.loggedIn = obj.loggedIn || false; + this.authenticated = false; - if (index >= 0) { - this.clients.splice(index, 1); } - else { - this.print("Failed at killing player", 33); + + /** + * @param {String} email + */ + generateUid(email) { + this.uid = getHashCodeFrom(String(email)); + } + + /** + * @param {Request} req + */ + updatePosition(req) { + + let data = decodeRequestEnvelope(req.request_message.buffer); + + this.latitude = data.latitude; + this.longitude = data.longitude; + //this.position.altitude = data.altitude; + + //console.log(`Updated position: ${data.latitude};${data.longitude}`); + + } + + 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; } } +/** + * @param {Player} player + */ export function getPlayerIndex(player) { let ip = player.remoteAddress; @@ -31,12 +111,18 @@ export function getPlayerIndex(player) { } +/** + * @param {Request} req + */ export function getPlayerByRequest(req) { return ( this.getPlayerByIP(req.connection.remoteAddress) ); } +/** + * @param {String} ip + */ export function getPlayerByIP(ip) { let ii = 0, length = this.clients.length; @@ -51,15 +137,35 @@ export function getPlayerByIP(ip) { } +/** + * @param {Request} connection + */ export function addPlayer(connection) { - this.clients.push({ - name: "rofl", + this.clients.push(new Player({ timeout: this.time, + connection: connection, + response: this.response, remotePort: connection.remotePort, - remoteAddress: connection.remoteAddress, - connection: connection - }); + remoteAddress: connection.remoteAddress + })); + +} + +/** + * @param {Player} player + */ +export function removePlayer(player) { + + let index = this.getPlayerIndex(player); + + if (index >= 0) { + this.clients.splice(index, 1); + this.print(`${player.remoteAddress} disconnected!`, 36); + } + else { + this.print("Failed at removing player", 33); + } } @@ -69,6 +175,14 @@ export function updatePlayers() { } export function savePlayers() { - this.print("Saving players into database"); + this.print("Saving players into database.."); + return void 0; +} + +/** + * @param {Player} player + */ +export function savePlayer(player) { + this.print(`${player.remoteAddress} saved into database`, 34); return void 0; } \ No newline at end of file diff --git a/src/process.js b/src/process.js index 7c2013d..f50ede9 100644 --- a/src/process.js +++ b/src/process.js @@ -1,10 +1,11 @@ import * as CFG from "../cfg"; -function processCommand(cmd, data) { +export function processCommand(cmd, data) { switch (cmd) { // How many active connections there are case "/clients": - this.print("There are many connected players!", 33); + let length = this.clients.length; + this.print(`${length} connected player${length === 1 ? "": "s"}!`, 33); break; // Kill the server case "/exit": @@ -19,7 +20,7 @@ export function stdinInput(data) { if (data.length < 1) return void 0; data = data.split(" "); var cmd = data[0]; - processCommand(); + this.processCommand(cmd, data); }; export function uncaughtException(excp) { diff --git a/src/utils.js b/src/utils.js index ac4638d..7eaa8d2 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,5 @@ +import proto from "./proto"; + /** * @param {Object} cls * @param {Object} prot @@ -13,4 +15,29 @@ export function inherit(cls, prot) { } }; -} \ No newline at end of file +} + +/** + * @param {Buffer} body + */ +export function decodeRequestEnvelope(body) { + return ( + proto.Networking.Envelopes.RequestEnvelope.decode(body) + ); +} + +/** + * http://stackoverflow.com/a/7616484/3367904 + * @param {String} str + * @return {String} + */ +export function getHashCodeFrom(str) { + var hash = 0, i, chr, len; + if (str.length === 0) return hash; + for (i = 0, len = str.length; i < len; i++) { + chr = str.charCodeAt(i); + hash = ((hash << 5) - hash) + chr; + hash |= 0; // Convert to 32bit integer + } + return hash; +}; \ No newline at end of file