diff --git a/Common/UITranslation.cs b/Common/UITranslation.cs index 7ceaf9f..deca880 100644 --- a/Common/UITranslation.cs +++ b/Common/UITranslation.cs @@ -52,8 +52,11 @@ public class UITranslation [Description("Theme")] public string Theme { get; set; } - - [Description("Enter your command")] + + [Description("Scheme")] + public string Scheme { get; set; } + + [Description("Enter your Command")] public string InputCommand { get; set; } #endregion @@ -61,11 +64,11 @@ public class UITranslation [Description("Zoom In")] public string ZoomIn { get; set; } - - [Description("ZoomOut")] + + [Description("Zoom Out")] public string ZoomOut { get; set; } - [Description("Clear map")] + [Description("Clear Map")] public string ClearMap { get; set; } [Description("Walk Here")] @@ -77,7 +80,7 @@ public class UITranslation [Description("100% IV")] public string TabSnipeIV100 { get; set; } - [Description("Rare pokemon")] + [Description("Rare Pokemon")] public string TabSnipeRarePokemon { get; set; } [Description("Others")] @@ -142,12 +145,12 @@ public class UITranslation [Description("Snipe Upgrade Setting")] public string MenuUpgradeFilterText { get; set; } - [Description("This pokemon can be evolve to below pokemon , please select the branch you want to evolve to")] public string EvolveConfirm { get; set; } [Description("Evolve Pokemon")] public string EvolvePopupCaption { get; set; } + [Description("Search & Filters")] public string FilterAndSearch { get; set; } @@ -238,22 +241,19 @@ public class UITranslation [Description("Longitude")] public string Longitude { get; set; } - [Description("Distance")] public string Distance { get; set; } - [Description("Close")] public string Close { get; set; } - - [Description("WalkHere")] + [Description("Walk Here")] public string WalkToHere { get; set; } [Description("CP")] public string GymDefenderCP { get; set; } - [Description("Gym Point")] + [Description("Gym Points")] public string GymPoints { get; set; } [Description("Pokestops: {0}")] @@ -267,10 +267,13 @@ public class UITranslation [Description("Transfered: {0}")] public string PokemonTransfered { get; set; } + [Description("HIDE")] public string Hide { get; set; } + [Description("SHOW")] public string Show { get; set; } + [Description("Transfer filter - {0}")] public string TransferFilterFormTitle { get; set; } #endregion diff --git a/Config/log4net.config b/Config/log4net.config new file mode 100644 index 0000000..c1ebe95 --- /dev/null +++ b/Config/log4net.config @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Config/log4net.unix.config b/Config/log4net.unix.config new file mode 100644 index 0000000..3b07772 --- /dev/null +++ b/Config/log4net.unix.config @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PoGo.NecroBot.Logic.csproj b/PoGo.NecroBot.Logic.csproj index 09b3387..aeba393 100644 --- a/PoGo.NecroBot.Logic.csproj +++ b/PoGo.NecroBot.Logic.csproj @@ -1,4 +1,4 @@ - + @@ -119,6 +119,9 @@ $(SolutionDir)\packages\LiteDB.3.1.0\lib\net35\LiteDB.dll True + + $(SolutionDir)\packages\log4net.2.0.3\lib\net40-full\log4net.dll + $(SolutionDir)\packages\Microsoft.AspNet.SignalR.Client.2.2.1\lib\net45\Microsoft.AspNet.SignalR.Client.dll True @@ -140,6 +143,24 @@ $(SolutionDir)\packages\SocketIoClientDotNet.0.9.13\lib\net45\SocketIoClientDotNet.dll True + + $(SolutionDir)\packages\SuperSocket.1.6.6.1\lib\net45\SuperSocket.Common.dll + + + $(SolutionDir)\packages\SuperSocket.1.6.6.1\lib\net45\SuperSocket.Facility.dll + + + $(SolutionDir)\packages\SuperSocket.1.6.6.1\lib\net45\SuperSocket.SocketBase.dll + + + $(SolutionDir)\packages\SuperSocket.Engine.1.6.6.1\lib\net45\SuperSocket.SocketEngine.dll + + + $(SolutionDir)\packages\SuperSocket.Engine.1.6.6.1\lib\net45\SuperSocket.SocketService.exe + + + $(SolutionDir)\packages\SuperSocket.WebSocket.1.6.6.1\lib\net45\SuperSocket.WebSocket.dll + True @@ -148,6 +169,7 @@ + $(SolutionDir)\packages\System.Console.4.3.0\lib\net46\System.Console.dll @@ -218,6 +240,9 @@ $(SolutionDir)\packages\Selenium.Support.3.3.0\lib\net40\WebDriver.Support.dll + + $(SolutionDir)\packages\WebSocketSharp.1.0.3-rc11\lib\websocket-sharp.dll + $(SolutionDir)\packages\WebSocket4Net.0.14.1\lib\net45\WebSocket4Net.dll True @@ -427,6 +452,7 @@ True Resources.resx + @@ -456,6 +482,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -582,6 +650,8 @@ Resources.Designer.cs + + @@ -614,4 +684,4 @@ --> - + \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 89b8026..13735ee 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -40,6 +40,6 @@ // [assembly: AssemblyVersion1("1.0.0.134")] -[assembly: AssemblyVersion("1.0.0.157")] +[assembly: AssemblyVersion("1.0.0.158")] [assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: AssemblyInformationalVersion("v1.0.0.157")] \ No newline at end of file +[assembly: AssemblyInformationalVersion("v1.0.0.158")] \ No newline at end of file diff --git a/Service/BotDataSocketClient.cs b/Service/BotDataSocketClient.cs new file mode 100644 index 0000000..7c534bc --- /dev/null +++ b/Service/BotDataSocketClient.cs @@ -0,0 +1,524 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using PoGo.NecroBot.Logic.Event; +using PoGo.NecroBot.Logic.Event.Snipe; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using POGOProtos.Enums; +using WebSocketSharp; +using Logger = PoGo.NecroBot.Logic.Logging.Logger; +using System.Runtime.Caching; +using System.Reflection; +using TinyIoC; + +namespace PoGo.NecroBot.Logic.Service +{ + public class BotDataSocketClient + { + public class SocketMessage + { + public string Header { get; set; } + public string Body { get; set; } + public long TimeTimestamp { get; set; } + public string Hash { get; set; } + } + public class SocketClientUpdate + { + public List Pokemons { get; set; } + + public List SnipeFailedPokemons { get; set; } + public List ExpiredPokemons { get; set; } + public string ClientVersion { get; set; } + public List ManualSnipes { get; set; } + public string Identitier { get; set; } + + public SocketClientUpdate() + { + Identitier = TinyIoCContainer.Current.Resolve().LogicSettings.DataSharingConfig.DataServiceIdentification; + ManualSnipes = new List(); + Pokemons = new List(); + SnipeFailedPokemons = new List(); + ExpiredPokemons = new List(); + ClientVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + + } + + public bool HasData() + { + return Pokemons.Count > 0 || SnipeFailedPokemons.Count > 0 || ExpiredPokemons.Count > 0; + } + } + private static SocketClientUpdate clientData = new SocketClientUpdate(); + + private const int POLLING_INTERVAL = 5000; + + public static void HandleEvent(AllBotSnipeEvent e, ISession session) + { + lock(clientData) + { + if(!string.IsNullOrEmpty(clientData.Identitier)) + { + clientData.ManualSnipes.Add(e.EncounterId); + } + } + } + public static void HandleEvent(IEvent evt, ISession session) + { + } + public static void HandleEvent(SnipeFailedEvent e, ISession sesion) + { + lock (clientData) + { + clientData.SnipeFailedPokemons.Add(e); + } + } + + public static void Listen(IEvent evt, ISession session) + { + dynamic eve = evt; + + try + { + HandleEvent(eve, session); + } + catch + { + } + } + + private static void HandleEvent(EncounteredEvent eve, ISession session) + { + lock (clientData) + { + if (eve.IsRecievedFromSocket || cache.Get(eve.EncounterId) != null) return; + clientData.Pokemons.Add(eve); + } + } + //private static SnipePokemonUpdateEvent lastEncouteredEvent; + private static void HandleEvent(SnipePokemonUpdateEvent eve, ISession session) + { + lock(clientData) + { + clientData.ExpiredPokemons.Add(eve.EncounterId); + } + } + private static string Serialize(dynamic evt) + { + var jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; + + // Add custom seriaizer to convert uong to string (ulong shoud not appear to json according to json specs) + jsonSerializerSettings.Converters.Add(new IdToStringConverter()); + + string json = JsonConvert.SerializeObject(evt, Formatting.None, jsonSerializerSettings); + //json = Regex.Replace(json, @"\\\\|\\(""|')|(""|')", match => { + // if (match.Groups[1].Value == "\"") return "\""; // Unescape \" + // if (match.Groups[2].Value == "\"") return "'"; // Replace " with ' + // if (match.Groups[2].Value == "'") return "\\'"; // Escape ' + // return match.Value; // Leave \\ and \' unchanged + //}); + return json; + } + + static List processing = new List(); + + public static String SHA256Hash(String value) + { + StringBuilder Sb = new StringBuilder(); + using (SHA256 hash = SHA256.Create()) + { + Encoding enc = Encoding.UTF8; + Byte[] result = hash.ComputeHash(enc.GetBytes(value)); + + foreach (Byte b in result) + Sb.Append(b.ToString("x2")); + } + + return Sb.ToString(); + } + + public static async Task Start(Session session, string encryptKey, CancellationToken cancellationToken) + { + + //Disable autosniper service until finger out how to make it work with API change + + await Task.Delay(30000, cancellationToken); //delay running 30s + + ServicePointManager.Expect100Continue = false; + + cancellationToken.ThrowIfCancellationRequested(); + + while (true && !termintated) + { + var socketURL = servers.Dequeue(); + Logger.Write($"Connecting to {socketURL} ...."); + await ConnectToServer(session, socketURL, encryptKey); + servers.Enqueue(socketURL); + } + + } + public static async Task ConnectToServer(ISession session, string socketURL, string encryptKey) + { + if (!string.IsNullOrEmpty(session.LogicSettings.DataSharingConfig.SnipeDataAccessKey)) + { + socketURL += "&access_key=" + session.LogicSettings.DataSharingConfig.SnipeDataAccessKey; + } + + int retries = 0; + using (var ws = new WebSocket(socketURL)) + { + ws.Log.Level = LogLevel.Fatal; ; + ws.Log.Output = (logData, message) => + { + //silenly, no log exception message to screen that scare people :) + }; + + ws.OnMessage += (sender, e) => { OnSocketMessageRecieved(session, sender, e); }; + + ws.Connect(); + while (true && !termintated) + { + try + { + if (retries == 3) + { + //failed to make connection to server times contiuing, temporary stop for 10 mins. + session.EventDispatcher.Send(new WarnEvent() + { + Message = $"Couldn't establish the connection to necrobot socket server : {socketURL}" + }); + if (session.LogicSettings.DataSharingConfig.EnableFailoverDataServers && servers.Count > 1) + { + break; + } + await Task.Delay(1 * 60 * 1000); + retries = 0; + } + + if (ws.ReadyState != WebSocketState.Open) + { + retries++; + ws.Connect(); + } + + while (ws.ReadyState == WebSocketState.Open && !termintated) + { + //Logger.Write("Connected to necrobot data service."); + retries = 0; + + if (ws.IsAlive && clientData.HasData()) + { + var data = JsonConvert.SerializeObject(clientData);// Serialize(processing); + clientData = new SocketClientUpdate(); + + var message = Encrypt(data, encryptKey); + var actualMessage = JsonConvert.SerializeObject(message); + ws.Send($"42[\"client-update\",{actualMessage}]"); + } + + await Task.Delay(POLLING_INTERVAL); + ws.Ping(); + } + } + catch (IOException) + { + session.EventDispatcher.Send(new WarnEvent + { + Message = "Disconnected from necrobot socket. New connection will be established when service becomes available..." + }); + + } + catch (Exception) + { + } + finally + { + //everytime disconnected with server bot wil reconnect after 15 sec + await Task.Delay(POLLING_INTERVAL); + } + } + } + } + + private static void OnSocketMessageRecieved(ISession session, object sender, MessageEventArgs e) + { + try + { + OnPokemonRemoved(session, e.Data); + OnPokemonUpdateData(session, e.Data); + OnPokemonData(session, e.Data); + OnSnipePokemon(session, e.Data); + OnServerMessage(session, e.Data); + } + catch (Exception ex) + { + Logger.Debug("ERROR TO ADD SNIPE< DEBUG ONLY " + ex.Message + "\r\n " + ex.StackTrace); + } + } + + private static DateTime lastWarningMessage = DateTime.MinValue; + private static bool termintated = false; + private static void OnServerMessage(ISession session, string message) + { + var match = Regex.Match(message, "42\\[\"server-message\",(.*)]"); + if (match != null && !string.IsNullOrEmpty(match.Groups[1].Value)) + { + if (message.Contains("The connection has been denied")) { + termintated = true; + } + var messag = match.Groups[1].Value; + if (message.Contains("The connection has been denied") && lastWarningMessage > DateTime.Now.AddMinutes(-5)) return; + lastWarningMessage = DateTime.Now; + session.EventDispatcher.Send(new NoticeEvent() + { + Message = "(SNIPE SERVER) " + match.Groups[1].Value + }); + } + } + + private static void ONFPMBridgeData(ISession session, string message) + { + var match = Regex.Match(message, "42\\[\"fpm\",(.*)]"); + if (match != null && !string.IsNullOrEmpty(match.Groups[1].Value)) + { + //var data = JsonConvert.DeserializeObject>(match.Groups[1].Value); + + // jjskuld - Ignore CS4014 warning for now. +#pragma warning disable 4014 + HumanWalkSnipeTask.AddFastPokemapItem(match.Groups[1].Value); +#pragma warning restore 4014 + } + } + + public static bool CheckIfPokemonBeenCaught(double lat, double lng, PokemonId id, ulong encounterId, + ISession session) + { + string uniqueCacheKey = + $"{session.Settings.Username}{Math.Round(lat, 6)}{id}{Math.Round(lng, 6)}"; + if (session.Cache.Get(uniqueCacheKey) != null) return true; + if (encounterId > 0 && session.Cache[encounterId.ToString()] != null) return true; + + return false; + } + + private static void OnPokemonUpdateData(ISession session, string message) + { + var match = Regex.Match(message, "42\\[\"pokemon-update\",(.*)]"); + if (match != null && !string.IsNullOrEmpty(match.Groups[1].Value)) + { + var data = JsonConvert.DeserializeObject(match.Groups[1].Value); + MSniperServiceTask.RemoveExpiredSnipeData(session, data.EncounterId); + } + } + + private static void OnPokemonRemoved(ISession session, string message) + { + var match = Regex.Match(message, "42\\[\"pokemon-remove\",(.*)]"); + if (match != null && !string.IsNullOrEmpty(match.Groups[1].Value)) + { + var data = JsonConvert.DeserializeObject(match.Groups[1].Value); + MSniperServiceTask.RemoveExpiredSnipeData(session, data.EncounterId); + } + } + + private static MemoryCache cache = new MemoryCache("dump"); + + //static int count = 0; + private static void OnPokemonData(ISession session, string message) + { + var match = Regex.Match(message, "42\\[\"pokemon\",(.*)]"); + if (match != null && !string.IsNullOrEmpty(match.Groups[1].Value)) + { + var data = JsonConvert.DeserializeObject(match.Groups[1].Value); + data.IsRecievedFromSocket = true; + if (Math.Abs(data.Latitude) > 90 || Math.Abs(data.Longitude) > 180) + { + return; + }; + + ulong.TryParse(data.EncounterId, out ulong encounterid); + if (encounterid > 0 && cache.Get(encounterid.ToString()) == null) + { + cache.Add(encounterid.ToString(), DateTime.Now, DateTime.Now.AddMinutes(15)); + } + + session.EventDispatcher.Send(data); + if (session.LogicSettings.DataSharingConfig.AutoSnipe) + { + var move1 = PokemonMove.MoveUnset; + var move2 = PokemonMove.MoveUnset; + Enum.TryParse(data.Move1, true, out move1); + Enum.TryParse(data.Move2, true, out move2); + + bool caught = CheckIfPokemonBeenCaught(data.Latitude, data.Longitude, + data.PokemonId, encounterid, session); + if (!caught) + { + var added = MSniperServiceTask.AddSnipeItem(session, new MSniperServiceTask.MSniperInfo2() + { + UniqueIdentifier = data.EncounterId, + Latitude = data.Latitude, + Longitude = data.Longitude, + EncounterId = encounterid, + SpawnPointId = data.SpawnPointId, + PokemonId = (short)data.PokemonId, + Level = data.Level, + Iv = data.IV, + Move1 = move1, + Move2 = move2, + ExpiredTime = data.ExpireTimestamp + }).Result; + if (added) + { + session.EventDispatcher.Send(new AutoSnipePokemonAddedEvent(data)); + } + } + } + } + } + + private static void OnSnipePokemon(ISession session, string message) + { + var match = Regex.Match(message, "42\\[\"snipe-pokemon\",(.*)]"); + if (match != null && !string.IsNullOrEmpty(match.Value) && !string.IsNullOrEmpty(match.Groups[1].Value)) + { + var data = JsonConvert.DeserializeObject(match.Groups[1].Value); + + //not your snipe item, return need more encrypt here and configuration to allow catch others item + if (string.IsNullOrEmpty(session.LogicSettings.DataSharingConfig.DataServiceIdentification) || + string.IsNullOrEmpty(data.RecieverId) || + data.RecieverId.ToLower() != session.LogicSettings.DataSharingConfig.DataServiceIdentification.ToLower()) return; + + var move1 = PokemonMove.Absorb; + var move2 = PokemonMove.Absorb; + Enum.TryParse(data.Move1, true, out move1); + Enum.TryParse(data.Move1, true, out move2); + ulong.TryParse(data.EncounterId, out ulong encounterid); + + bool caught = CheckIfPokemonBeenCaught(data.Latitude, data.Longitude, data.PokemonId, encounterid, + session); + if (caught) + { + Logger.Write("[SNIPE IGNORED] - Your snipe pokemon has already been cautgh by bot", + Logic.Logging.LogLevel.Sniper); + return; + } + + MSniperServiceTask.AddSnipeItem(session, new MSniperServiceTask.MSniperInfo2() + { + UniqueIdentifier = data.EncounterId, + Latitude = data.Latitude, + Longitude = data.Longitude, + EncounterId = encounterid, + SpawnPointId = data.SpawnPointId, + Level = data.Level, + PokemonId = (short)data.PokemonId, + Iv = data.IV, + Move1 = move1, + ExpiredTime = data.ExpireTimestamp, + Move2 = move2 + }, true).Wait(); + } + } + private static Queue servers = new Queue(); + public static Task StartAsync(Session session, string encryptKey, + CancellationToken cancellationToken = default(CancellationToken)) + { + var config = session.LogicSettings.DataSharingConfig; + + if (config.EnableSyncData) + { + servers.Enqueue(config.DataRecieverURL); + + if (config.EnableFailoverDataServers) + { + foreach (var item in config.FailoverDataServers.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) + { + servers.Enqueue(item); + } + } + } + + return Task.Run(() => Start(session, encryptKey, cancellationToken), cancellationToken); + } + + public static SocketMessage Encrypt(string message, string encryptKey) + { + var encryptedtulp = Encrypt(message, encryptKey, false); + + var socketMessage = new SocketMessage() + { + TimeTimestamp = (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds, + Header = encryptedtulp.Item1, + Body = encryptedtulp.Item2 + }; + socketMessage.Hash = CalculateMD5Hash($"{socketMessage.TimeTimestamp}{socketMessage.Body}{socketMessage.Header}"); + + return socketMessage; + } + public static string CalculateMD5Hash(string input) + { + // step 1, calculate MD5 hash from input + + MD5 md5 = MD5.Create(); + + byte[] inputBytes = Encoding.ASCII.GetBytes(input); + + byte[] hash = md5.ComputeHash(inputBytes); + + // step 2, convert byte array to hex string + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < hash.Length; i++) + + { + + sb.Append(hash[i].ToString("X2")); + + } + + return sb.ToString(); + + } + + + public static Tuple Encrypt(string toEncrypt, string key, bool useHashing) + { + byte[] keyArray; + byte[] toEncryptArray = Encoding.UTF8.GetBytes(toEncrypt); + + if (useHashing) + { + MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider(); + keyArray = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(key)); + } + else + keyArray = Encoding.UTF8.GetBytes(key); + + var tdes = new TripleDESCryptoServiceProvider() + { + Key = keyArray + }; + // tdes.Mode = CipherMode.CBC; // which is default + // tdes.Padding = PaddingMode.PKCS7; // which is default + + //Console.WriteLine("iv: {0}", Convert.ToBase64String(tdes.IV)); + + ICryptoTransform cTransform = tdes.CreateEncryptor(); + byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, + toEncryptArray.Length); + string iv = Convert.ToBase64String(tdes.IV); + string message = Convert.ToBase64String(resultArray, 0, resultArray.Length); + return new Tuple(iv, message); + } + + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/DropItemHandler.cs b/Service/WebSocketHandler/ActionCommands/DropItemHandler.cs new file mode 100644 index 0000000..74ae6b7 --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/DropItemHandler.cs @@ -0,0 +1,27 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using POGOProtos.Inventory.Item; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class DropItemHandler : IWebSocketRequestHandler + { + public DropItemHandler() + { + Command = "DropItem"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await RecycleItemsTask.DropItem(session, (ItemId) message.ItemId, (int) message.Count); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/EvolvePokemonHandler.cs b/Service/WebSocketHandler/ActionCommands/EvolvePokemonHandler.cs new file mode 100644 index 0000000..6120a4a --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/EvolvePokemonHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class EvolvePokemonHandler : IWebSocketRequestHandler + { + public EvolvePokemonHandler() + { + Command = "EvolvePokemon"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await EvolveSpecificPokemonTask.Execute(session, (ulong) message.PokemonId); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/FastpokemapHandler.cs b/Service/WebSocketHandler/ActionCommands/FastpokemapHandler.cs new file mode 100644 index 0000000..ccb5ebc --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/FastpokemapHandler.cs @@ -0,0 +1,29 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class FastpokemapHandler : IWebSocketRequestHandler + { + public FastpokemapHandler() + { + Command = "Fastpokemap"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + CatchState.AddFastPokemapItem(message.Data); + + await HumanWalkSnipeTask.AddFastPokemapItem(message.Data); + //Console.WriteLine(JsonConvert.DeserializeObject(message.Data)); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/FavoritePokemonHandler.cs b/Service/WebSocketHandler/ActionCommands/FavoritePokemonHandler.cs new file mode 100644 index 0000000..02c0fd0 --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/FavoritePokemonHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class FavoritePokemonHandler : IWebSocketRequestHandler + { + public FavoritePokemonHandler() + { + Command = "FavoritePokemon"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await FavoritePokemonTask.Execute(session, (ulong) message.PokemonId, (bool) message.Favorite); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/HumanSnipePriorityPokemonHandler.cs b/Service/WebSocketHandler/ActionCommands/HumanSnipePriorityPokemonHandler.cs new file mode 100644 index 0000000..0a5da9f --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/HumanSnipePriorityPokemonHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class HumanSnipePriorityPokemonHandler : IWebSocketRequestHandler + { + public HumanSnipePriorityPokemonHandler() + { + Command = "SnipePokemon"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await HumanWalkSnipeTask.TargetPokemonSnip(session, (string) message.Id); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/HumanSnipeRemovePokemonHandler.cs b/Service/WebSocketHandler/ActionCommands/HumanSnipeRemovePokemonHandler.cs new file mode 100644 index 0000000..a2e386c --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/HumanSnipeRemovePokemonHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class HumanSnipeRemovePokemonHandler : IWebSocketRequestHandler + { + public HumanSnipeRemovePokemonHandler() + { + Command = "RemovePokemon"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await HumanWalkSnipeTask.RemovePokemonFromQueue(session, (string) message.Id); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/LevelUpPokemonHandler.cs b/Service/WebSocketHandler/ActionCommands/LevelUpPokemonHandler.cs new file mode 100644 index 0000000..d40274d --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/LevelUpPokemonHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class LevelUpPokemonHandler : IWebSocketRequestHandler + { + public string Command { get; private set; } + + public LevelUpPokemonHandler() + { + Command = "LevelUpPokemon"; + } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await LevelUpSpecificPokemonTask.Execute(session, (ulong) message.PokemonId); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/SetConfigHandler.cs b/Service/WebSocketHandler/ActionCommands/SetConfigHandler.cs new file mode 100644 index 0000000..21037b8 --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/SetConfigHandler.cs @@ -0,0 +1,69 @@ +#region using directives + +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class SetConfigHandler : IWebSocketRequestHandler + { + public SetConfigHandler() + { + Command = "SetConfig"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + var profilePath = Path.Combine(Directory.GetCurrentDirectory(), ""); + var profileConfigPath = Path.Combine(profilePath, "config"); + var authFile = Path.Combine(profileConfigPath, "auth.json"); + var configFile = Path.Combine(profileConfigPath, "config.json"); + + var jsonSerializeSettings = new JsonSerializerSettings + { + DefaultValueHandling = DefaultValueHandling.Include, + Formatting = Formatting.Indented, + Converters = new JsonConverter[] {new StringEnumConverter {CamelCaseText = true}} + }; + + await Task.Run(() => + { + try + { + var authJson = JsonConvert.SerializeObject((JObject) message.AuthJson, jsonSerializeSettings); + if (!string.IsNullOrEmpty(authJson) && authJson != "null") + File.WriteAllText(authFile, authJson, Encoding.UTF8); + } + catch (Exception) + { + // ignored + } + }); + + await Task.Run(() => + { + try + { + var configJson = JsonConvert.SerializeObject((JObject) message.ConfigJson, jsonSerializeSettings); + if (!string.IsNullOrEmpty(configJson) && configJson != "null") + File.WriteAllText(configFile, configJson, Encoding.UTF8); + } + catch (Exception) + { + // ignored + } + }); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/SetMoveToTargetHandler.cs b/Service/WebSocketHandler/ActionCommands/SetMoveToTargetHandler.cs new file mode 100644 index 0000000..4aaba5e --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/SetMoveToTargetHandler.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class SetMoveToTargetHandler : IWebSocketRequestHandler + { + public string Command { get; private set; } + + public SetMoveToTargetHandler() + { + Command = "SetMoveToTarget"; + } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await SetMoveToTargetTask.Execute((double) message.Latitude, (double) message.Longitude, (string) message.FortId); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/SetTrainerNicknameHandler.cs b/Service/WebSocketHandler/ActionCommands/SetTrainerNicknameHandler.cs new file mode 100644 index 0000000..3645bc8 --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/SetTrainerNicknameHandler.cs @@ -0,0 +1,61 @@ +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Event; +using PoGo.NecroBot.Logic.Model; +using PoGo.NecroBot.Logic.State; +using POGOProtos.Networking.Responses; +using SuperSocket.WebSocket; + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class SetTrainerNicknameHandler : IWebSocketRequestHandler + { + public string Command { get; private set; } + + public SetTrainerNicknameHandler() + { + Command = "SetNickname"; + } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + string nickname = message.Data; + + if (nickname.Length > 15) + { + session.EventDispatcher.Send(new NoticeEvent() + { + Message = "You selected too long Desired name, max length: 15!" + }); + return; + } + if (nickname == session.Profile.PlayerData.Username) return; + + + using (var blocker = new BlockableScope(session, BotActions.UpdateProfile)) + { + if (!await blocker.WaitToRun()) return; + + var res = await session.Client.Misc.ClaimCodename(nickname); + if (res.Status == ClaimCodenameResponse.Types.Status.Success) + { + session.EventDispatcher.Send(new NoticeEvent() + { + Message = $"Your name is now: {res.Codename}" + }); + + session.EventDispatcher.Send(new NicknameUpdateEvent() + { + Nickname = res.Codename + }); + } + else + { + session.EventDispatcher.Send(new NoticeEvent() + { + Message = $"Couldn't change your nickname" + }); + } + } + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/TransferPokemonHandler.cs b/Service/WebSocketHandler/ActionCommands/TransferPokemonHandler.cs new file mode 100644 index 0000000..8ac5671 --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/TransferPokemonHandler.cs @@ -0,0 +1,34 @@ +#region using directives + +using System.Collections.Generic; +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class TransferPokemonHandler : IWebSocketRequestHandler + { + public TransferPokemonHandler() + { + Command = "TransferPokemon"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await TransferPokemonTask.Execute( + session, + session.CancellationTokenSource.Token, + new List + { + (ulong) message.PokemonId + } + ); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/ActionCommands/UpgradePokemonHandler.cs b/Service/WebSocketHandler/ActionCommands/UpgradePokemonHandler.cs new file mode 100644 index 0000000..efd1cd5 --- /dev/null +++ b/Service/WebSocketHandler/ActionCommands/UpgradePokemonHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.ActionCommands +{ + public class UpgradePokemonHandler : IWebSocketRequestHandler + { + public UpgradePokemonHandler() + { + Command = "UpgradePokemon"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await UpgradeSinglePokemonTask.Execute(session, (ulong) message.PokemonId, (bool) message.Max); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/EncodingHelper.cs b/Service/WebSocketHandler/EncodingHelper.cs new file mode 100644 index 0000000..5a00807 --- /dev/null +++ b/Service/WebSocketHandler/EncodingHelper.cs @@ -0,0 +1,43 @@ +#region using directives + +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler +{ + internal class EncodingHelper + { + public static string Serialize(dynamic evt) + { + var jsonSerializerSettings = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All}; + + // Add custom seriaizer to convert uong to string (ulong shoud not appear to json according to json specs) + jsonSerializerSettings.Converters.Add(new IdToStringConverter()); + + return JsonConvert.SerializeObject(evt, Formatting.None, jsonSerializerSettings); + } + + public class IdToStringConverter : JsonConverter + { + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + var jt = JToken.ReadFrom(reader); + return jt.Value(); + } + + public override bool CanConvert(Type objectType) + { + return typeof(long) == objectType || typeof(ulong) == objectType; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value.ToString()); + } + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Events/ConfigResponce.cs b/Service/WebSocketHandler/GetCommands/Events/ConfigResponce.cs new file mode 100644 index 0000000..893efcb --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Events/ConfigResponce.cs @@ -0,0 +1,16 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events +{ + public class ConfigResponce : IWebSocketResponce + { + public ConfigResponce(dynamic data, string requestID) + { + Command = "ConfigWeb"; + Data = data; + RequestID = requestID; + } + + public string RequestID { get; } + public string Command { get; } + public dynamic Data { get; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Events/EggListResponce.cs b/Service/WebSocketHandler/GetCommands/Events/EggListResponce.cs new file mode 100644 index 0000000..f3d3c6f --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Events/EggListResponce.cs @@ -0,0 +1,16 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events +{ + public class EggListResponce : IWebSocketResponce + { + public EggListResponce(dynamic data, string requestID) + { + Command = "EggListWeb"; + Data = data; + RequestID = requestID; + } + + public string RequestID { get; } + public string Command { get; } + public dynamic Data { get; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Events/ItemListResponce.cs b/Service/WebSocketHandler/GetCommands/Events/ItemListResponce.cs new file mode 100644 index 0000000..2c6f036 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Events/ItemListResponce.cs @@ -0,0 +1,16 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events +{ + internal class ItemListResponce : IWebSocketResponce + { + public ItemListResponce(dynamic data, string requestID) + { + Command = "ItemListWeb"; + Data = data; + RequestID = requestID; + } + + public string RequestID { get; } + public string Command { get; } + public dynamic Data { get; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Events/PokemonListResponce.cs b/Service/WebSocketHandler/GetCommands/Events/PokemonListResponce.cs new file mode 100644 index 0000000..ecd9bf5 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Events/PokemonListResponce.cs @@ -0,0 +1,22 @@ +#region using directives + +using PoGo.NecroBot.Logic.Event; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events +{ + public class PokemonListResponce : IWebSocketResponce, IEvent + { + public PokemonListResponce(dynamic data, string requestID) + { + Command = "PokemonListWeb"; + Data = data; + RequestID = requestID; + } + + public string RequestID { get; } + public string Command { get; } + public dynamic Data { get; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Events/SnipeListResponce.cs b/Service/WebSocketHandler/GetCommands/Events/SnipeListResponce.cs new file mode 100644 index 0000000..a37b9a5 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Events/SnipeListResponce.cs @@ -0,0 +1,16 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events +{ + internal class SnipeListResponce : IWebSocketResponce + { + public SnipeListResponce(dynamic data, string requestID) + { + Command = "HumanWalkSnipEvent"; + Data = data; + RequestID = requestID; + } + + public string RequestID { get; } + public string Command { get; } + public dynamic Data { get; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Events/TrainerProfileResponce.cs b/Service/WebSocketHandler/GetCommands/Events/TrainerProfileResponce.cs new file mode 100644 index 0000000..c0fc68f --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Events/TrainerProfileResponce.cs @@ -0,0 +1,16 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events +{ + internal class TrainerProfileResponce : IWebSocketResponce + { + public TrainerProfileResponce(dynamic data, string requestID) + { + Command = "TrainerProfile"; + Data = data; + RequestID = requestID; + } + + public string RequestID { get; } + public string Command { get; } + public dynamic Data { get; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Events/WebResponce.cs b/Service/WebSocketHandler/GetCommands/Events/WebResponce.cs new file mode 100644 index 0000000..4621474 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Events/WebResponce.cs @@ -0,0 +1,9 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events +{ + public class WebResponce : IWebSocketResponce + { + public string RequestID { get; set; } + public string Command { get; set; } + public dynamic Data { get; set; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/GetConfigHandler.cs b/Service/WebSocketHandler/GetCommands/GetConfigHandler.cs new file mode 100644 index 0000000..faf2981 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/GetConfigHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands +{ + internal class GetConfigHandler : IWebSocketRequestHandler + { + public GetConfigHandler() + { + Command = "GetConfig"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await GetConfigTask.Execute(session, webSocketSession, (string) message.RequestID); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/GetEggListHandler.cs b/Service/WebSocketHandler/GetCommands/GetEggListHandler.cs new file mode 100644 index 0000000..2d6b1f3 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/GetEggListHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands +{ + internal class GetEggListHandler : IWebSocketRequestHandler + { + public GetEggListHandler() + { + Command = "GetEggList"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await GetEggListTask.Execute(session, webSocketSession, (string) message.RequestID); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/GetItemsListHandler.cs b/Service/WebSocketHandler/GetCommands/GetItemsListHandler.cs new file mode 100644 index 0000000..f25a63b --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/GetItemsListHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands +{ + internal class GetItemsListHandler : IWebSocketRequestHandler + { + public GetItemsListHandler() + { + Command = "GetItemsList"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await GetItemListTask.Execute(session, webSocketSession, (string) message.RequestID); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/GetPokemonListHandler.cs b/Service/WebSocketHandler/GetCommands/GetPokemonListHandler.cs new file mode 100644 index 0000000..9343fcc --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/GetPokemonListHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands +{ + public class GetPokemonListHandler : IWebSocketRequestHandler + { + public GetPokemonListHandler() + { + Command = "GetPokemonList"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await GetPokemonListTask.Execute(session, webSocketSession, (string) message.RequestID); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/GetPokemonSettingsHandler.cs b/Service/WebSocketHandler/GetCommands/GetPokemonSettingsHandler.cs new file mode 100644 index 0000000..d59254a --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/GetPokemonSettingsHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands +{ + public class GetPokemonSettingsHandler : IWebSocketRequestHandler + { + public GetPokemonSettingsHandler() + { + Command = "GetPokemonSettings"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await GetPokemonSettingsTask.Execute(session, webSocketSession, (string) message.RequestID); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/GetPokemonSnipeListHandler.cs b/Service/WebSocketHandler/GetCommands/GetPokemonSnipeListHandler.cs new file mode 100644 index 0000000..8f0d62b --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/GetPokemonSnipeListHandler.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands +{ + class GetPokemonSnipeListHandler : IWebSocketRequestHandler + { + public string Command { get; private set; } + + public GetPokemonSnipeListHandler() + { + Command = "PokemonSnipeList"; + } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await HumanWalkSnipeTask.ExecuteFetchData(session); + //await GetPokemonSnipeListTask.Execute(session, webSocketSession, (string)message.RequestID); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/GetTrainerProfileHandler.cs b/Service/WebSocketHandler/GetCommands/GetTrainerProfileHandler.cs new file mode 100644 index 0000000..b27fd6e --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/GetTrainerProfileHandler.cs @@ -0,0 +1,26 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands +{ + internal class GetTrainerProfileHandler : IWebSocketRequestHandler + { + public GetTrainerProfileHandler() + { + Command = "GetTrainerProfile"; + } + + public string Command { get; } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + await GetTrainerProfileTask.Execute(session, webSocketSession, (string) message.RequestID); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Helpers/ConfigWeb.cs b/Service/WebSocketHandler/GetCommands/Helpers/ConfigWeb.cs new file mode 100644 index 0000000..56ce0ae --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Helpers/ConfigWeb.cs @@ -0,0 +1,10 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Helpers +{ + internal class ConfigWeb + { + public object AuthJson { get; set; } + public object AuthSchemaJson { get; set; } + public object ConfigJson { get; set; } + public object ConfigSchemaJson { get; set; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Helpers/EggListWeb.cs b/Service/WebSocketHandler/GetCommands/Helpers/EggListWeb.cs new file mode 100644 index 0000000..dc08c9e --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Helpers/EggListWeb.cs @@ -0,0 +1,8 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Helpers +{ + internal class EggListWeb + { + public object Incubators { get; set; } + public object UnusedEggs { get; set; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Helpers/PokemonListWeb.cs b/Service/WebSocketHandler/GetCommands/Helpers/PokemonListWeb.cs new file mode 100644 index 0000000..a12a49e --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Helpers/PokemonListWeb.cs @@ -0,0 +1,26 @@ +#region using directives + +using PoGo.NecroBot.Logic.PoGoUtils; +using POGOProtos.Data; +using PoGo.NecroBot.Logic.State; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Helpers +{ + public class PokemonListWeb + { + public PokemonData Base; + private readonly ISession _session; + + public PokemonListWeb(ISession session, PokemonData data) + { + Base = data; + _session = session; + } + + public double IvPerfection => PokemonInfo.CalculatePokemonPerfection(Base); + public double Level => PokemonInfo.GetLevel(Base); + public int FamilyCandies => PokemonInfo.GetCandy(_session, Base).Result; + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Helpers/TrainerProfileWeb.cs b/Service/WebSocketHandler/GetCommands/Helpers/TrainerProfileWeb.cs new file mode 100644 index 0000000..392b942 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Helpers/TrainerProfileWeb.cs @@ -0,0 +1,21 @@ +#region using directives + +using POGOProtos.Data; +using POGOProtos.Data.Player; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Helpers +{ + internal class TrainerProfileWeb + { + public PlayerData Profile; + public PlayerStats Stats; + + public TrainerProfileWeb(PlayerData profile, PlayerStats stats) + { + Profile = profile; + Stats = stats; + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Tasks/GetConfigTask.cs b/Service/WebSocketHandler/GetCommands/Tasks/GetConfigTask.cs new file mode 100644 index 0000000..f672f93 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Tasks/GetConfigTask.cs @@ -0,0 +1,46 @@ +#region using directives + +using System.IO; +using System.Text; +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Helpers; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks +{ + internal class GetConfigTask + { + public static async Task Execute(ISession session, WebSocketSession webSocketSession, string requestID) + { + await Task.Run(() => + { + var profilePath = Path.Combine(Directory.GetCurrentDirectory(), ""); + var profileConfigPath = Path.Combine(profilePath, "config"); + + var authFile = Path.Combine(profileConfigPath, "auth.json"); + var authSchemaFile = Path.Combine(profileConfigPath, "auth.schema.json"); + var authJson = File.ReadAllText(authFile, Encoding.UTF8); + var authSchemaJson = File.ReadAllText(authSchemaFile, Encoding.UTF8); + + var configFile = Path.Combine(profileConfigPath, "config.json"); + var configSchemaFile = Path.Combine(profileConfigPath, "config.schema.json"); + var configJson = File.ReadAllText(configFile, Encoding.UTF8); + var configSchemaJson = File.ReadAllText(configSchemaFile, Encoding.UTF8); + + var list = new ConfigWeb + { + AuthJson = authJson, + AuthSchemaJson = authSchemaJson, + ConfigJson = configJson, + ConfigSchemaJson = configSchemaJson + }; + + webSocketSession.Send(EncodingHelper.Serialize(new ConfigResponce(list, requestID))); + }); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Tasks/GetEggListTask.cs b/Service/WebSocketHandler/GetCommands/Tasks/GetEggListTask.cs new file mode 100644 index 0000000..617c1bf --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Tasks/GetEggListTask.cs @@ -0,0 +1,43 @@ +#region using directives + +using System.Linq; +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Helpers; +using PoGo.NecroBot.Logic.State; +using POGOProtos.Inventory.Item; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks +{ + internal class GetEggListTask + { + public static async Task Execute(ISession session, WebSocketSession webSocketSession, string requestID) + { + // using (var blocker = new BlockableScope(session, BotActions.Eggs)) + { + // if (!await blocker.WaitToRun()) return; + + var incubators = (await session.Inventory.GetEggIncubators()) + .Where(x => x.UsesRemaining > 0 || x.ItemId == ItemId.ItemIncubatorBasicUnlimited) + .OrderByDescending(x => x.ItemId == ItemId.ItemIncubatorBasicUnlimited) + .ToList(); + + var unusedEggs = (await session.Inventory.GetEggs()) + .Where(x => string.IsNullOrEmpty(x.EggIncubatorId)) + .OrderBy(x => x.EggKmWalkedTarget - x.EggKmWalkedStart) + .ToList(); + + + var list = new EggListWeb + { + Incubators = incubators, + UnusedEggs = unusedEggs + }; + webSocketSession.Send(EncodingHelper.Serialize(new EggListResponce(list, requestID))); + } + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Tasks/GetItemListTask.cs b/Service/WebSocketHandler/GetCommands/Tasks/GetItemListTask.cs new file mode 100644 index 0000000..5f13b59 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Tasks/GetItemListTask.cs @@ -0,0 +1,25 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks +{ + internal class GetItemListTask + { + public static async Task Execute(ISession session, WebSocketSession webSocketSession, string requestID) + { + // using (var blocker = new BlockableScope(session, BotActions.ListItems)) + { + //if (!await blocker.WaitToRun()) return; + + var allItems = await session.Inventory.GetItems(); + webSocketSession.Send(EncodingHelper.Serialize(new ItemListResponce(allItems, requestID))); + } + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonListTask.cs b/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonListTask.cs new file mode 100644 index 0000000..b301e07 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonListTask.cs @@ -0,0 +1,30 @@ +#region using directives + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Helpers; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks +{ + internal class GetPokemonListTask + { + public static async Task Execute(ISession session, WebSocketSession webSocketSession, string requestID) + { + //using (var blocker = new BlockableScope(session, BotActions.ListItems)) + { + //if (!await blocker.WaitToRun()) return; + + var allPokemonInBag = await session.Inventory.GetHighestsCp(1000); + var list = new List(); + allPokemonInBag.ToList().ForEach(o => list.Add(new PokemonListWeb(session, o))); + webSocketSession.Send(EncodingHelper.Serialize(new PokemonListResponce(list, requestID))); + } + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonSettingsTask.cs b/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonSettingsTask.cs new file mode 100644 index 0000000..9ec6cd9 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonSettingsTask.cs @@ -0,0 +1,30 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks +{ + internal class GetPokemonSettingsTask + { + public static async Task Execute(ISession session, WebSocketSession webSocketSession, string requestID) + { + //using (var blocker = new BlockableScope(session, BotActions.PokemonSettings)) + { + // if (!await blocker.WaitToRun()) return; + + var settings = await session.Inventory.GetPokemonSettings(); + webSocketSession.Send(EncodingHelper.Serialize(new WebResponce + { + Command = "PokemonSettings", + Data = settings, + RequestID = requestID + })); + } + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonSnipeListTask.cs b/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonSnipeListTask.cs new file mode 100644 index 0000000..129296f --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Tasks/GetPokemonSnipeListTask.cs @@ -0,0 +1,22 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks +{ + internal class GetPokemonSnipeListTask + { + public static async Task Execute(ISession session, WebSocketSession webSocketSession, string requestID) + { + var allItems = await HumanWalkSnipeTask.GetCurrentQueueItems(session); + + webSocketSession.Send(EncodingHelper.Serialize(new SnipeListResponce(allItems, requestID))); + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/GetCommands/Tasks/GetTrainerProfileTask.cs b/Service/WebSocketHandler/GetCommands/Tasks/GetTrainerProfileTask.cs new file mode 100644 index 0000000..7148cb6 --- /dev/null +++ b/Service/WebSocketHandler/GetCommands/Tasks/GetTrainerProfileTask.cs @@ -0,0 +1,30 @@ +#region using directives + +using System.Linq; +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Events; +using PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Helpers; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler.GetCommands.Tasks +{ + internal class GetTrainerProfileTask + { + public static async Task Execute(ISession session, WebSocketSession webSocketSession, string requestID) + { + //using (var blocker = new BlockableScope(session, BotActions.GetProfile)) + { + // if (!await blocker.WaitToRun()) return; + + var playerStats = (await session.Inventory.GetPlayerStats()).FirstOrDefault(); + if (playerStats == null) + return; + var tmpData = new TrainerProfileWeb(session.Profile.PlayerData, playerStats); + webSocketSession.Send(EncodingHelper.Serialize(new TrainerProfileResponce(tmpData, requestID))); + } + } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/IWebSocketRequestHandler.cs b/Service/WebSocketHandler/IWebSocketRequestHandler.cs new file mode 100644 index 0000000..db8db51 --- /dev/null +++ b/Service/WebSocketHandler/IWebSocketRequestHandler.cs @@ -0,0 +1,16 @@ +#region using directives + +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler +{ + internal interface IWebSocketRequestHandler + { + string Command { get; } + Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message); + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/IWebSocketResponce.cs b/Service/WebSocketHandler/IWebSocketResponce.cs new file mode 100644 index 0000000..851898b --- /dev/null +++ b/Service/WebSocketHandler/IWebSocketResponce.cs @@ -0,0 +1,9 @@ +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler +{ + internal interface IWebSocketResponce + { + string RequestID { get; } + string Command { get; } + dynamic Data { get; } + } +} \ No newline at end of file diff --git a/Service/WebSocketHandler/WebSocketEventManager.cs b/Service/WebSocketHandler/WebSocketEventManager.cs new file mode 100644 index 0000000..6078620 --- /dev/null +++ b/Service/WebSocketHandler/WebSocketEventManager.cs @@ -0,0 +1,59 @@ +#region using directives + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using PoGo.NecroBot.Logic.State; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service.WebSocketHandler +{ + internal class WebSocketEventManager + { + private readonly Dictionary _registerdHandlers = + new Dictionary(); + + public void RegisterHandler(string actionName, IWebSocketRequestHandler action) + { + try + { + _registerdHandlers.Add(actionName, action); + } + catch + { + // ignore + } + } + + public async Task Handle(ISession session, WebSocketSession webSocketSession, dynamic message) + { + if (_registerdHandlers.ContainsKey((string) message.Command)) + { + await _registerdHandlers[(string) message.Command].Handle(session, webSocketSession, message); + } + } + + // Registers all IWebSocketRequestHandler's automatically. + + public static WebSocketEventManager CreateInstance() + { + var manager = new WebSocketEventManager(); + + var type = typeof(IWebSocketRequestHandler); + var types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(s => s.GetTypes()) + .Where(p => type.IsAssignableFrom(p) && p.IsClass); + + foreach (var plugin in types) + { + var instance = (IWebSocketRequestHandler) Activator.CreateInstance(plugin); + manager.RegisterHandler(instance.Command, instance); + } + + return manager; + } + } +} \ No newline at end of file diff --git a/Service/WebSocketInterface.cs b/Service/WebSocketInterface.cs new file mode 100644 index 0000000..7ea652d --- /dev/null +++ b/Service/WebSocketInterface.cs @@ -0,0 +1,233 @@ +#region using directives + +using System.Linq; +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PoGo.NecroBot.Logic.Service.WebSocketHandler; +using PoGo.NecroBot.Logic.Common; +using PoGo.NecroBot.Logic.Event; +using PoGo.NecroBot.Logic.Logging; +using PoGo.NecroBot.Logic.State; +using PoGo.NecroBot.Logic.Tasks; +using SuperSocket.SocketBase; +using SuperSocket.SocketBase.Config; +using SuperSocket.WebSocket; + +#endregion + +namespace PoGo.NecroBot.Logic.Service +{ + public class WebSocketInterface + { + private readonly WebSocketServer _server; + private readonly Session _session; + private readonly WebSocketEventManager _websocketHandler; + private PokeStopListEvent _lastPokeStopList; + private ProfileEvent _lastProfile; + + public WebSocketInterface(int port, Session session) + { + _session = session; + var translations = session.Translation; + _server = new WebSocketServer(); + _websocketHandler = WebSocketEventManager.CreateInstance(); + var config = new ServerConfig + { + Name = "NecroWebSocket", + Mode = SocketMode.Tcp, + MaxRequestLength = int.MaxValue, + Certificate = new CertificateConfig + { + FilePath = @"cert.pfx", + Password = "necro" + }, + Listeners = new List + { + new ListenerConfig + { + Ip = "Any", + Port = port, + Security = "tls" + }, + new ListenerConfig + { + Ip = "Any", + Port = port + 1, + Security = "none" + } + } + }; + + var setupComplete = _server.Setup(config); + + if (setupComplete == false) + { + Logger.Write(translations.GetTranslation(TranslationString.WebSocketFailStart, port), LogLevel.Error); + return; + } + + _server.NewMessageReceived += HandleMessage; + _server.NewSessionConnected += HandleSession; + + if (_server.Start()) + { + Logger.Write(translations.GetTranslation(TranslationString.WebSocketStarted, port, port + 1), LogLevel.Info); + + } + else + { + Logger.Write($"Counld't start socket server at port {port}, this port may be in use or blocked, please change your config to another port and restart bot if you want to use web gui.", LogLevel.Error); + } + } + + private void Broadcast(string message) + { + foreach (var session in _server.GetAllSessions()) + { + try + { + session.Send(message); + } + catch (Exception) + { +#if DEBUG + //Logger.Write(ex.Message); +#endif + } + } + } + + private void HandleEvent(PokeStopListEvent evt) + { + if (_lastPokeStopList != null) + { + _lastPokeStopList.Forts.RemoveAll(x => evt.Forts.Any(t => x.Id == x.Id)); + _lastPokeStopList.Forts.AddRange(evt.Forts); + } + else + _lastPokeStopList = evt; + } + + private void HandleEvent(ProfileEvent evt) + { + _lastProfile = evt; + } + + private async void HandleMessage(WebSocketSession session, string message) + { + switch (message) + { + case "PokemonList": + await PokemonListTask.Execute(_session); + break; + case "EggsList": + await EggsListTask.Execute(_session); + break; + case "InventoryList": + await InventoryListTask.Execute(_session); + break; + case "PokemonSnipeList": + await HumanWalkSnipeTask.ExecuteFetchData(_session); + break; + } + + // Setup to only send data back to the session that requested it. + try + { + dynamic decodedMessage = JObject.Parse(message); + var handle = _websocketHandler?.Handle(_session, session, decodedMessage); + if (handle != null) + await handle; + } + catch (Exception) + { +#if DEBUG + //Logger.Write(ex.Message); +#endif + } + + // When we first get a message from the web socket, turn off log buffering. + // This allows us to flush out buffered LogEvent messages to the GUI. + Logger.TurnOffLogBuffering(); + } + + private void HandleSession(WebSocketSession session) + { + if (_lastProfile != null) + session.Send(Serialize(_lastProfile)); + + if (_lastPokeStopList != null) + session.Send(Serialize(_lastPokeStopList)); + + try + { + session.Send(Serialize(new UpdatePositionEvent + { + Latitude = _session.Client.CurrentLatitude, + Longitude = _session.Client.CurrentLongitude + })); + } + catch (Exception ) + { +#if DEBUG + //Logger.Write(ex.Message); +#endif + } + } + + public void HandleEvent(IEvent evt) + { + } + + public void Listen(IEvent evt, Session session) + { + dynamic eve = evt; + + try + { + HandleEvent(eve); + } + catch (Exception ) + { +#if DEBUG + //Logger.Write(ex.Message); +#endif + // ignored + } + + Broadcast(Serialize(eve)); + } + + private static string Serialize(dynamic evt) + { + var jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; + + // Add custom seriaizer to convert uong to string (ulong shoud not appear to json according to json specs) + jsonSerializerSettings.Converters.Add(new IdToStringConverter()); + + return JsonConvert.SerializeObject(evt, Formatting.None, jsonSerializerSettings); + } + } + + public class IdToStringConverter : JsonConverter + { + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + var jt = JToken.ReadFrom(reader); + return jt.Value(); + } + + public override bool CanConvert(Type objectType) + { + return typeof(long) == objectType || typeof(ulong) == objectType; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value.ToString()); + } + } +} \ No newline at end of file diff --git a/packages.config b/packages.config index 4619692..95127ef 100644 --- a/packages.config +++ b/packages.config @@ -9,6 +9,7 @@ + @@ -22,6 +23,9 @@ + + + @@ -67,4 +71,5 @@ + \ No newline at end of file