protected AParser() { Server = new Core.Server {Name = "test.bitpir.at"}; Channel = new Channel {Name = "#test"}; Server.AddChannel(Channel); Bot = new Bot {Name = "[XG]TestBot"}; Channel.AddBot(Bot); }
void OnMessage(IWebSocketConnection aContext, string aMessage) { Log.Info("OnMessage(" + aContext.ConnectionInfo.ClientIpAddress + ", " + aMessage + ")"); var currentUser = (from user in _users where user.Connection == aContext select user).SingleOrDefault(); var request = JsonConvert.DeserializeObject<Request>(aMessage); #if !UNSAFE try { #endif // no pass, no way if (request.Password != Password) { Log.Error("OnMessage(" + aContext.ConnectionInfo.ClientIpAddress + ") bad password"); // exit return; } switch (request.Type) { case Request.Types.AddServer: AddServer(request.Name); break; case Request.Types.RemoveServer: RemoveServer(request.Guid); break; case Request.Types.AddChannel: AddChannel(request.Guid, request.Name); break; case Request.Types.RemoveChannel: RemoveChannel(request.Guid); break; case Request.Types.ActivateObject: ActivateObject(request.Guid); break; case Request.Types.DeactivateObject: DeactivateObject(request.Guid); break; case Request.Types.Search: var packets = FilteredPackets(AllPackets(request.IgnoreOfflineBots), request.Guid); UnicastBlock(currentUser, "Packet", packets); var bots = DistinctBots(packets); UnicastBlock(currentUser, "Bot", bots); currentUser.IgnoreOfflineBots = request.IgnoreOfflineBots; currentUser.LastSearch = request.Guid; currentUser.LastLoadedBots = bots; currentUser.LastViewedBot = Guid.Empty; currentUser.LastLoadedPackets = packets; break; case Request.Types.SearchExternal: var searchExternal = Searches.WithGuid(request.Guid); if (searchExternal != null) { ExternalSearch[] results = new ExternalSearch[0]; try { var uri = new Uri("http://xg.bitpir.at/index.php?show=search&action=external&search=" + searchExternal.Name + "&xg=" + Settings.Instance.XgVersion); var req = HttpWebRequest.Create(uri); var response = req.GetResponse(); StreamReader sr = new StreamReader(response.GetResponseStream()); string text = sr.ReadToEnd(); response.Close(); results = JsonConvert.DeserializeObject<ExternalSearch[]>(text, JsonSerializerSettings); } catch (Exception ex) { Log.Fatal("OnMessage() cant load external search for " + searchExternal.Name, ex); } Unicast(currentUser, new Response { Type = Response.Types.SearchExternal, Data = results }); } break; case Request.Types.AddSearch: string name = request.Name; var obj = Searches.Named(name); if (obj == null) { obj = new Core.Object {Name = name}; Searches.Add(obj); } break; case Request.Types.RemoveSearch: var search = Searches.WithGuid(request.Guid); if (search != null) { foreach (var user in _users) { if (user.LastSearch == request.Guid) { user.LastSearch = Guid.Empty; } } Searches.Remove(search); } break; case Request.Types.Searches: var searches = new List<Core.Object>(); searches.Add(_search0Day); searches.Add(_search0Week); searches.Add(_searchDownloads); searches.Add(_searchEnabled); searches.AddRange(Searches.All); Unicast(currentUser, new Response { Type = Response.Types.Searches, Data = searches }); break; case Request.Types.Servers: UnicastBlock(currentUser, "Server", Servers.All); break; case Request.Types.ChannelsFromServer: var channels = (from server in Servers.All from channel in server.Channels where channel.ParentGuid == request.Guid select channel).ToList(); UnicastBlock(currentUser, "Channel", channels); currentUser.LastViewedServer = request.Guid; currentUser.LastLoadedChannels = channels; break; case Request.Types.PacketsFromBot: var botPackets = (from server in Servers.All from channel in server.Channels from bot in channel.Bots from packet in bot.Packets where packet.ParentGuid == request.Guid select packet).ToList(); UnicastBlock(currentUser, "Packet", botPackets); currentUser.LastViewedBot = request.Guid; currentUser.LastLoadedPackets = botPackets; break; case Request.Types.Statistics: //response = Statistic2Json(); break; case Request.Types.Snapshots: Unicast(currentUser, new Response { Type = Response.Types.Snapshots, Data = Snapshots2Flot(Snapshots) }); break; case Request.Types.Files: UnicastBlock(currentUser, "File", Files.All); break; case Request.Types.CloseServer: break; case Request.Types.ParseXdccLink: string[] link = request.Name.Substring(7).Split('/'); string serverName = link[0]; string channelName = link[2]; string botName = link[3]; int packetId = int.Parse(link[4].Substring(1)); // checking server Core.Server serv = Servers.Server(serverName); if (serv == null) { Servers.Add(serverName); serv = Servers.Server(serverName); } serv.Enabled = true; // checking channel Channel chan = serv.Channel(channelName); if (chan == null) { serv.AddChannel(channelName); chan = serv.Channel(channelName); } chan.Enabled = true; // checking bot Bot tBot = chan.Bot(botName); if (tBot == null) { tBot = new Bot {Name = botName}; chan.AddBot(tBot); } // checking packet Packet pack = tBot.Packet(packetId); if (pack == null) { pack = new Packet {Id = packetId, Name = link[5]}; tBot.AddPacket(pack); } pack.Enabled = true; break; } #if !UNSAFE } catch (Exception ex) { Log.Fatal("OnMessage(" + aContext.ConnectionInfo.ClientIpAddress + ", " + aMessage + ")", ex); } #endif }
public void RegisterParser(Server.Irc.AParser aParser) { IrcParser = aParser; IrcParser.ParsingError += delegate(string aData) { EventParsingError = aData; }; IrcParser.AddDownload += delegate(Packet aPack, long aChunk, IPAddress aIp, int aPort) { EventPacket = aPack; EventChunk = aChunk; EventIp = aIp; EventPort = aPort; }; IrcParser.RemoveDownload += delegate(Bot aBot) { EventBot = aBot; }; IrcParser.SendData += delegate(Core.Server aServer, string aData) { Assert.AreEqual(Server, aServer); EventData = aData; }; IrcParser.JoinChannel += delegate(Core.Server aServer, Channel aChannel) { Assert.AreEqual(Server, aServer); EventChannel = aChannel; }; IrcParser.CreateTimer += delegate(Core.Server aServer, AObject aObject, int aTime, bool aOverride) { Assert.AreEqual(Server, aServer); EventObject = aObject; EventTime = aTime; EventOverride = aOverride; }; IrcParser.RequestFromBot += delegate(Core.Server aServer, Bot aBot) { Assert.AreEqual(Server, aServer); EventBot = aBot; }; IrcParser.UnRequestFromBot += delegate(Core.Server aServer, Bot aBot) { Assert.AreEqual(Server, aServer); EventBot = aBot; }; }
void BotDisconnect(Bot aBot) { foreach (var kvp in _downloads) { if (kvp.Key.Parent == aBot) { kvp.Value.Connection.Disconnect(); break; } } }
void RequestFromBot(Bot aBot) { if (aBot != null) { if (aBot.State == Bot.States.Idle) { // check if the packet is already downloaded, or active - than disable it and get the next one Packet tPacket = aBot.OldestActivePacket(); while (tPacket != null) { Int64 tChunk = FileActions.NextAvailablePartSize(tPacket.RealName != "" ? tPacket.RealName : tPacket.Name, tPacket.RealSize != 0 ? tPacket.RealSize : tPacket.Size); if (tChunk == -1) { _log.Warn("RequestFromBot(" + aBot + ") packet #" + tPacket.Id + " (" + tPacket.Name + ") is already in use"); tPacket.Enabled = false; tPacket.Commit(); tPacket = aBot.OldestActivePacket(); } else { string name = Core.Helper.ShrinkFileName(tPacket.RealName != "" ? tPacket.RealName : tPacket.Name, 0); if (_latestPacketRequests.ContainsKey(name)) { double time = (_latestPacketRequests[name] - DateTime.Now).TotalSeconds; if (time > 0) { _log.Warn("RequestFromBot(" + aBot + ") packet name " + tPacket.Name + " is blocked for " + time + "ms"); CreateTimer(aBot, (int) time + 1, false); return; } } if (_server.Connected) { _log.Info("RequestFromBot(" + aBot + ") requesting packet #" + tPacket.Id + " (" + tPacket.Name + ")"); SendData("PRIVMSG " + aBot.Name + " :\u0001XDCC SEND " + tPacket.Id + "\u0001"); if (_latestPacketRequests.ContainsKey(name)) { _latestPacketRequests.Remove(name); } _latestPacketRequests.Add(name, DateTime.Now.AddSeconds(Settings.Instance.SamePacketRequestTime)); // statistics Statistic.Instance.Increase(StatisticType.PacketsRequested); } // create a timer to re request if the bot didnt recognized the privmsg CreateTimer(aBot, Settings.Instance.BotWaitTime, false); break; } } } } }
void UnRequestFromBot(Bot aBot) { if (aBot != null) // && myServer[aBot.Name] != null) { _log.Info("UnregisterFromBot(" + aBot + ")"); SendData("PRIVMSG " + aBot.Name + " :\u0001XDCC REMOVE\u0001"); CreateTimer(aBot, Settings.Instance.CommandWaitTime, false); // statistics Statistic.Instance.Increase(StatisticType.PacketsRemoved); } }
protected void FireUnRequestFromBot(Core.Server aServer, Bot aBot) { if (UnRequestFromBot != null) { UnRequestFromBot(aServer, aBot); } }
void IrcParserUnRequestFromBot(Core.Server aServer, Bot aBot) { if (_server == aServer) { UnRequestFromBot(aBot); } }
protected void FireRemoveDownload(Bot aBot) { if (RemoveDownload != null) { RemoveDownload(aBot); } }
protected override void Parse(Core.Server aServer, string aRawData, string aMessage, string[] aCommands) { ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType + "(" + aServer.Name + ")"); string tUserName = aCommands[0].Split('!')[0]; Channel tChan = aServer.Channel(aCommands[2]); Bot tBot = aServer.Bot(tUserName); #region VERSION if (aMessage == "VERSION") { log.Info("Parse() VERSION: " + Settings.Instance.IrcVersion); FireSendData(aServer, "NOTICE " + tUserName + " :\u0001VERSION " + Settings.Instance.IrcVersion + "\u0001"); return; } #endregion #region XGVERSION if (aMessage == "XGVERSION") { log.Info("Parse() XGVERSION: " + Settings.Instance.XgVersion); FireSendData(aServer, "NOTICE " + tUserName + " :\u0001XGVERSION " + Settings.Instance.XgVersion + "\u0001"); return; } #endregion #region DCC DOWNLOAD MESSAGE if (aMessage.StartsWith("DCC") && tBot != null) { Packet tPacket = tBot.OldestActivePacket(); if (tPacket != null) { if (tPacket.Connected) { log.Error("Parse() ignoring dcc from " + tBot + " because " + tPacket + " is already connected"); } else { bool isOk = false; int tPort = 0; Int64 tChunk = 0; string[] tDataList = aMessage.Split(' '); if (tDataList[1] == "SEND") { log.Info("Parse() DCC from " + tBot); // if the name of the file contains spaces, we have to replace em if (aMessage.StartsWith("DCC SEND \"")) { Match tMatch = Regex.Match(aMessage, "DCC SEND \"(?<packet_name>.+)\"(?<bot_data>[^\"]+)$"); if (tMatch.Success) { aMessage = "DCC SEND " + tMatch.Groups["packet_name"].ToString().Replace(" ", "_").Replace("'", "") + tMatch.Groups["bot_data"]; tDataList = aMessage.Split(' '); } } #region IP CALCULATING try { // this works not in mono?! tBot.Ip = IPAddress.Parse(tDataList[3]); } catch (FormatException) { #region WTF - FLIP THE IP BECAUSE ITS REVERSED?! string ip; try { ip = new IPAddress(long.Parse(tDataList[3])).ToString(); } catch (Exception ex) { log.Fatal("Parse() " + tBot + " - can not parse bot ip from string: " + aMessage, ex); return; } string realIp = ""; int pos = ip.LastIndexOf('.'); try { realIp += ip.Substring(pos + 1) + "."; ip = ip.Substring(0, pos); pos = ip.LastIndexOf('.'); realIp += ip.Substring(pos + 1) + "."; ip = ip.Substring(0, pos); pos = ip.LastIndexOf('.'); realIp += ip.Substring(pos + 1) + "."; ip = ip.Substring(0, pos); pos = ip.LastIndexOf('.'); realIp += ip.Substring(pos + 1); } catch (Exception ex) { log.Fatal("Parse() " + tBot + " - can not parse bot ip '" + ip + "' from string: " + aMessage, ex); return; } log.Info("Parse() IP parsing failed, using this: " + realIp); try { tBot.Ip = IPAddress.Parse(realIp); } catch (Exception ex) { log.Fatal("Parse() " + tBot + " - can not parse bot ip from string: " + aMessage, ex); return; } #endregion } #endregion try { tPort = int.Parse(tDataList[4]); } catch (Exception ex) { log.Fatal("Parse() " + tBot + " - can not parse bot port from string: " + aMessage, ex); return; } // we cant connect to port <= 0 if (tPort <= 0) { log.Error("Parse() " + tBot + " submitted wrong port: " + tPort + ", disabling packet"); tPacket.Enabled = false; // statistics Statistic.Instance.Increase(StatisticType.BotConnectsFailed); } else { tPacket.RealName = tDataList[2]; try { tPacket.RealSize = Int64.Parse(tDataList[5]); } catch (Exception ex) { log.Fatal("Parse() " + tBot + " - can not parse packet size from string: " + aMessage, ex); return; } tChunk = FileActions.NextAvailablePartSize(tPacket.RealName, tPacket.RealSize); if (tChunk < 0) { log.Error("Parse() file for " + tPacket + " from " + tBot + " already in use, disabling packet"); tPacket.Enabled = false; FireUnRequestFromBot(aServer, tBot); } else if (tChunk > 0) { log.Info("Parse() try resume from " + tBot + " for " + tPacket + " @ " + tChunk); FireSendData(aServer, "PRIVMSG " + tBot.Name + " :\u0001DCC RESUME " + tPacket.RealName + " " + tPort + " " + tChunk + "\u0001"); } else { isOk = true; } } } else if (tDataList[1] == "ACCEPT") { log.Info("Parse() DCC resume accepted from " + tBot); try { tPort = int.Parse(tDataList[3]); } catch (Exception ex) { log.Fatal("Parse() " + tBot + " - can not parse bot port from string: " + aMessage, ex); return; } try { tChunk = Int64.Parse(tDataList[4]); } catch (Exception ex) { log.Fatal("Parse() " + tBot + " - can not parse packet chunk from string: " + aMessage, ex); return; } isOk = true; } if (isOk) { log.Info("Parse() downloading from " + tBot + " - Starting: " + tChunk + " - Size: " + tPacket.RealSize); FireAddDownload(tPacket, tChunk, tBot.Ip, tPort); } tPacket.Commit(); } } else { log.Error("Parse() DCC not activated from " + tBot); } } #endregion #region DCC INFO MESSAGE else if (tChan != null) { bool insertBot = false; if (tBot == null) { insertBot = true; tBot = new Bot {Name = tUserName, Connected = true, LastMessage = "initial creation", LastContact = DateTime.Now}; } bool isParsed = false; Match tMatch; #region PACKET /SLOT / QUEUE INFO if (true) { tMatch = Regex.Match(aMessage, Magicstring + " ([0-9]*) (pack(s|)|Pa(c|)ket(e|)|Fil[e]+s) " + Magicstring + "\\s*(?<slot_cur>[0-9]*) (of|von) (?<slot_total>[0-9]*) (slot(s|)|Pl(a|�|.)tz(e|)) (open|opened|free|frei|in use|offen)(, ((Queue|Warteschlange): (?<queue_cur>[0-9]*)(\\/| of )(?<queue_total>[0-9]*),|).*(Record( [a-zA-Z]+|): (?<record>[0-9.]*)(K|)B\\/s|)|)", RegexOptions.IgnoreCase); if (tMatch.Success) { isParsed = true; int valueInt; if (int.TryParse(tMatch.Groups["slot_cur"].ToString(), out valueInt)) { tBot.InfoSlotCurrent = valueInt; } if (int.TryParse(tMatch.Groups["slot_total"].ToString(), out valueInt)) { tBot.InfoSlotTotal = valueInt; } if (int.TryParse(tMatch.Groups["queue_cur"].ToString(), out valueInt)) { tBot.InfoQueueCurrent = valueInt; } if (int.TryParse(tMatch.Groups["queue_total"].ToString(), out valueInt)) { tBot.InfoQueueTotal = valueInt; } if (tBot.InfoSlotCurrent > tBot.InfoSlotTotal) { tBot.InfoSlotTotal = tBot.InfoSlotCurrent; } if (tBot.InfoQueueCurrent > tBot.InfoQueueTotal) { tBot.InfoQueueTotal = tBot.InfoQueueCurrent; } // uhm, there is a free slot and we are still waiting? if (tBot.InfoSlotCurrent > 0 && tBot.State == Bot.States.Waiting) { tBot.State = Bot.States.Idle; FireCreateTimer(aServer, tBot, 0, false); } } } #endregion #region BANDWIDTH if (!isParsed) { tMatch = Regex.Match(aMessage, Magicstring + " ((Bandwidth Usage|Bandbreite) " + Magicstring + "|)\\s*(Current|Derzeit): (?<speed_cur>[0-9.]*)(?<speed_cur_end>(K|)(i|)B)(\\/s|s)(,|)(.*Record: (?<speed_max>[0-9.]*)(?<speed_max_end>(K|)(i|))B(\\/s|s)|)", RegexOptions.IgnoreCase); if (tMatch.Success) { isParsed = true; string speedCurEnd = tMatch.Groups["speed_cur_end"].ToString().ToLower(); string speedMaxEnd = tMatch.Groups["speed_max_end"].ToString().ToLower(); string speedCur = tMatch.Groups["speed_cur"].ToString(); string speedMax = tMatch.Groups["speed_max"].ToString(); if (Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator == ",") { speedCur = speedCur.Replace('.', ','); speedMax = speedMax.Replace('.', ','); } double valueDouble; if (double.TryParse(speedCur, out valueDouble)) { tBot.InfoSpeedCurrent = speedCurEnd.StartsWith("k") ? (Int64) (valueDouble * 1024) : (Int64) valueDouble; } if (double.TryParse(speedMax, out valueDouble)) { tBot.InfoSpeedMax = speedMaxEnd.StartsWith("k") ? (Int64) (valueDouble * 1024) : (Int64) valueDouble; } } } #endregion #region PACKET INFO Packet newPacket = null; if (!isParsed) { // what is this damn char \240 and how to rip it off ??? tMatch = Regex.Match(aMessage, "#(?<pack_id>\\d+)(\u0240|�|)\\s+(\\d*)x\\s+\\[\\s*(�|)\\s*(?<pack_size>[\\<\\>\\d.]+)(?<pack_add>[BbGgiKMs]+)\\]\\s+(?<pack_name>.*)", RegexOptions.IgnoreCase); if (tMatch.Success) { isParsed = true; try { int tPacketId; try { tPacketId = int.Parse(tMatch.Groups["pack_id"].ToString()); } catch (Exception ex) { log.Fatal("Parse() " + tBot + " - can not parse packet id from string: " + aMessage, ex); return; } Packet tPack = tBot.Packet(tPacketId); if (tPack == null) { tPack = new Packet(); newPacket = tPack; tPack.Id = tPacketId; tBot.AddPacket(tPack); } tPack.LastMentioned = DateTime.Now; string name = RemoveSpecialIrcCharsFromPacketName(tMatch.Groups["pack_name"].ToString()); if (tPack.Name != name && tPack.Name != "") { tPack.Enabled = false; if (!tPack.Connected) { tPack.RealName = ""; tPack.RealSize = 0; } } tPack.Name = name; double tPacketSizeFormated; string stringSize = tMatch.Groups["pack_size"].ToString().Replace("<", "").Replace(">", ""); if (Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator == ",") { stringSize = stringSize.Replace('.', ','); } double.TryParse(stringSize, out tPacketSizeFormated); string tPacketAdd = tMatch.Groups["pack_add"].ToString().ToLower(); if (tPacketAdd == "k" || tPacketAdd == "kb") { tPack.Size = (Int64) (tPacketSizeFormated * 1024); } else if (tPacketAdd == "m" || tPacketAdd == "mb") { tPack.Size = (Int64) (tPacketSizeFormated * 1024 * 1024); } else if (tPacketAdd == "g" || tPacketAdd == "gb") { tPack.Size = (Int64) (tPacketSizeFormated * 1024 * 1024 * 1024); } if (tPack.Commit()) { log.Info("Parse() updated " + tPack + " from " + tBot); } } catch (FormatException) {} } } #endregion // insert bot if ok if (insertBot) { if (isParsed) { tChan.AddBot(tBot); log.Info("Parse() inserted " + tBot); } } // and insert packet _AFTER_ this if (newPacket != null) { tBot.AddPacket(newPacket); log.Info("Parse() inserted " + newPacket + " into " + tBot); } #if DEBUG #region NOT NEEDED INFOS if (!isParsed) { tMatch = Regex.Match(aMessage, Magicstring + " To request .* type .*", RegexOptions.IgnoreCase); if (tMatch.Success) { return; } tMatch = Regex.Match(aMessage, ".*\\/(msg|ctcp) .* xdcc (info|send) .*", RegexOptions.IgnoreCase); if (tMatch.Success) { return; } tMatch = Regex.Match(aMessage, Magicstring + " To list a group, type .*", RegexOptions.IgnoreCase); if (tMatch.Success) { return; } tMatch = Regex.Match(aMessage, "Total offered(\\!|): (\\[|)[0-9.]*\\s*[BeGgiKMsTty]+(\\]|)\\s*Total transfer(r|)ed: (\\[|)[0-9.]*\\s*[BeGgiKMsTty]+(\\]|)", RegexOptions.IgnoreCase); if (tMatch.Success) { return; } tMatch = Regex.Match(aMessage, ".* (brought to you|powered|sp(o|0)ns(o|0)red) by .*", RegexOptions.IgnoreCase); if (tMatch.Success) { return; } tMatch = Regex.Match(aMessage, Magicstring + " .*" + tChan.Name + " " + Magicstring, RegexOptions.IgnoreCase); if (tMatch.Success) { return; } } #endregion #region COULD NOT PARSE if (!isParsed) // && tBot.Packets.Count() > 0) { FireParsingError("[DCC Info] " + tBot.Name + " : " + RemoveSpecialIrcChars(aMessage)); } #endregion #endif } #endregion if (tBot != null) { tBot.Commit(); } if (tChan != null) { tChan.Commit(); } }
public void RemoveBot(Bot aBot) { Remove(aBot); }
public void AddBot(Bot aBot) { Add(aBot); }
public void Serialize() { var jsonSerializerSettings = new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat, DateParseHandling = DateParseHandling.DateTime, DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind }; var part = new FilePart {Connected = true, Enabled = true, Guid = Guid.Empty}; Assert.AreEqual( "{\"StartSize\":0,\"StopSize\":0,\"CurrentSize\":0,\"MissingSize\":0,\"TimeMissing\":0,\"Speed\":0,\"State\":0,\"Checked\":false,\"ParentGuid\":\"00000000-0000-0000-0000-000000000000\",\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Name\":\"\",\"Connected\":true,\"Enabled\":true}", JsonConvert.SerializeObject(part, jsonSerializerSettings) ); var packet = new Packet { Name = "Test Packet", Connected = true, Enabled = true, Guid = Guid.Empty, LastMentioned = DateTime.Now, LastUpdated = DateTime.Now, Part = part }; Assert.AreEqual( "{\"Part\":{\"StartSize\":0,\"StopSize\":0,\"CurrentSize\":0,\"MissingSize\":0,\"TimeMissing\":0,\"Speed\":0,\"State\":0,\"Checked\":false,\"ParentGuid\":\"00000000-0000-0000-0000-000000000000\",\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Name\":\"\",\"Connected\":true,\"Enabled\":true},\"Name\":\"Test Packet\",\"Id\":-1,\"Size\":0,\"RealSize\":0,\"RealName\":\"\",\"LastUpdated\":\"" + JsonDate(packet.LastUpdated) + "\",\"LastMentioned\":\"" + JsonDate(packet.LastMentioned) + "\",\"Next\":false,\"ParentGuid\":\"00000000-0000-0000-0000-000000000000\",\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Connected\":true,\"Enabled\":true}", JsonConvert.SerializeObject(packet, jsonSerializerSettings) ); var bot = new Bot { Name = "Test Bot", Connected = true, Enabled = true, Guid = Guid.Empty, InfoQueueCurrent = 16, InfoQueueTotal = 16, InfoSlotCurrent = 16, InfoSlotTotal = 16, InfoSpeedCurrent = 16, InfoSpeedMax = 16, LastMessage = "Test Message", QueuePosition = 16, QueueTime = 16, State = Bot.States.Idle, LastContact = DateTime.Now }; bot.AddPacket(packet); Assert.AreEqual( "{\"State\":0,\"LastMessage\":\"Test Message\",\"LastMessageTime\":\"" + JsonDate(bot.LastMessageTime) + "\",\"LastContact\":\"" + JsonDate(bot.LastContact) + "\",\"QueuePosition\":16,\"QueueTime\":16,\"InfoSpeedMax\":16,\"InfoSpeedCurrent\":16,\"InfoSlotTotal\":16,\"InfoSlotCurrent\":16,\"InfoQueueTotal\":16,\"InfoQueueCurrent\":16,\"Speed\":0,\"HasNetworkProblems\":false,\"ParentGuid\":\"00000000-0000-0000-0000-000000000000\",\"Guid\":\"00000000-0000-0000-0000-000000000000\",\"Name\":\"Test Bot\",\"Connected\":true,\"Enabled\":true}", JsonConvert.SerializeObject(bot, jsonSerializerSettings) ); }