/// <summary> /// Salesforce disconnects at random the client and the client must be re-connected and also re-subscribed. /// </summary> /// <param name="sender"></param> /// <param name="message"></param> private void ErrorExtension_ConnectionError(object sender, string message) { // authentication failure if (string.Equals(message, "403::Handshake denied", StringComparison.OrdinalIgnoreCase) || string.Equals(message, "403:denied_by_security_policy:create_denied", StringComparison.OrdinalIgnoreCase) || string.Equals(message, "403::unknown client", StringComparison.OrdinalIgnoreCase) ) { _logger.LogWarning("Handled CometD Exception: {message}", message); // 1. Disconnect Disconnect(); // 2. Try (x) times to re-authenticate Reauthenticate(); _logger.LogDebug("Re-authenticating {name}...", nameof(BayeuxClient)); // 3. Recreate BayeuxClient and populate it with a new transport with new security headers. InitBayeuxClient(); // 4. Invoke the Reconnect Event Reconnect?.Invoke(this, true); } else { _logger.LogError($"{nameof(StreamingClient)} failed with the following message: {message}"); } }
private void ErrorExtension_ConnectionError( object sender, string e) { // authentication failure if (string.Equals(e, "403::Handshake denied", StringComparison.OrdinalIgnoreCase) || string.Equals(e, "403:denied_by_security_policy:create_denied", StringComparison.OrdinalIgnoreCase) || string.Equals(e, "403::unknown client", StringComparison.OrdinalIgnoreCase)) { _logger.LogWarning("Handled CometD Exception: {message}", e); // 1. Disconnect existing client. Disconnect(); // 2. Invalidate the access token. _tokenResponse.Invalidate(); _logger.LogDebug("Invalidate token for {name} ...", nameof(BayeuxClient)); // 3. Recreate BayeuxClient and populate it with a new transport with new security headers. CreateBayeuxClient(); // 4. Invoke the Reconnect Event Reconnect?.Invoke(this, true); } else { _logger.LogError("{name} failed with the following message: {message}", nameof(ResilientStreamingClient), e); } }
public void Connect(Reconnect reconnect) { OnDisconnectHasBeenCalled = false; _incomingEncryption = new RC4(IncomingKey); _outgoingEncryption = new RC4(OutgoingKey); try { Log.Info("Connecting no using proxy!"); _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); _socket.Connect(new IPEndPoint(IPAddress.Parse(reconnect.Host), reconnect.Port)); _socket.NoDelay = true; _socket.ReceiveTimeout = 5000; _socket.SendTimeout = 5000; Disconnected = false; Start(); _onConnect?.Invoke(); } catch (Exception e) { Log.Error("Disconnecting due to error : " + e.Message); Disconnect(DisconnectReason.ExceptionOnConnection.SetDetails(e.Message)); } }
/// <summary> /// Salesforce disconnects at random the client and the client must be re-connected and also re-subscribed. /// </summary> /// <param name="sender"></param> /// <param name="message"></param> private void ErrorExtension_ConnectionError(object sender, string message) { // authentication failure if (message.ToLower() == "403::Handshake denied" || message.ToLower() == "403:denied_by_security_policy:create_denied" || message.ToLower() == "403::unknown client" ) { _logger.LogError($"Handled CometD Exception: {message}"); _logger.LogDebug($"Re-authenticating BayeuxClient..."); // 1. Disconnect Disconnect(); _logger.LogDebug($"Disconnecting {nameof(BayeuxClient)}..."); // 2. try (x) times to re-authenticate Reauthenticate(); _logger.LogDebug($"Re-authenticating {nameof(BayeuxClient)}..."); // 3. populate a new transport with new security headers. InitBayeuxClient(); _logger.LogDebug($"Re-Init {nameof(BayeuxClient)}..."); // invoke event Reconnect?.Invoke(this, true); } else { _logger.LogError($"{nameof(StreamingClient)} failed with the following message: {message}"); } }
public Advice(Reconnect reconnect, TimeSpan interval, TimeSpan timeout) { Reconnect = reconnect; Interval = interval; Timeout = timeout; }
public void AddReconnect(int accountId, Reconnect rcp) { if (rcp == null) { return; } var rInfo = new ReconInfo(rcp.GameId, rcp.Key, DateTime.Now.AddSeconds(ReconTTL)); _recon.TryAdd(accountId, rInfo); }
public void Reconnect(Reconnect pkt) { if (Account == null) { Disconnect("Tried to reconnect an client with a null account..."); return; } Log.Trace("Reconnecting client ({0}) @ {1} to {2}...", Account.Name, IP, pkt.Name); Manager.ConMan.AddReconnect(Account.AccountId, pkt); SendPacket(pkt); }
public void Connect(Reconnect reconnect) { _incomingEncryption = new RC4(Utility.HexStringToBytes(IncomingKey)); _outgoingEncryption = new RC4(Utility.HexStringToBytes(OutgoingKey)); _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); _socket.Connect(new IPEndPoint(IPAddress.Parse(reconnect.Host), reconnect.Port)); Disconnected = false; _socket.NoDelay = true; _socket.ReceiveTimeout = 5000; _socket.SendTimeout = 5000; Start(); _onConnect?.Invoke(); }
static void Main(string[] args) { Packets.Load("Packets.json"); Reconnect reconnect = new Reconnect() { Host = "54.93.78.148", Port = 2050, GameId = -2, KeyTime = 0, Key = new byte[0] }; NetClient client = new NetClient(reconnect); client.Hook(PacketType.Failure, (p) => { Console.WriteLine("Failure: " + ((FailurePacket)p).ErrorDescription); }); client.Hook(PacketType.MapInfo, (p) => { LoadPacket load = new LoadPacket() { CharId = 2, IsFromArena = false }; client.SendPacket(load); }); client.Hook(PacketType.Update, (p) => { client.SendPacket(new UpdateAckPacket()); }); client.Hook(PacketType.NewTick, (p) => { Console.WriteLine("NEW_TICK, id: " + ((NewTickPacket)p).TickId); }); HelloPacket hello = new HelloPacket() { BuildVersion = "X31.2.3", GameId = reconnect.GameId, Guid = RSA.Instance.Encrypt(""), Password = RSA.Instance.Encrypt(""), Secret = RSA.Instance.Encrypt(""), GameNet = "rotmg", PlayPlatform = "rotmg" }; client.SendPacket(hello); Console.ReadKey(); }
public void QuakeToWorld(World newWorld) { if (!Persist || this is Realm) { Closed = true; } BroadcastPacket(new ShowEffect() { EffectType = EffectType.Earthquake }, null, PacketPriority.Low); Timers.Add(new WorldTimer(8000, (w, t) => { var rcpNotPaused = new Reconnect() { Host = "", Port = 2050, GameId = newWorld.Id, Name = newWorld.SBName }; var rcpPaused = new Reconnect() { Host = "", Port = 2050, GameId = World.Nexus, Name = "Nexus" }; foreach (var plr in w.Players.Values) { plr.Client.Reconnect( plr.HasConditionEffect(ConditionEffects.Paused) && plr.SpectateTarget == null ? rcpPaused : rcpNotPaused); } })); if (!Persist) { Timers.Add(new WorldTimer(20000, (w2, t2) => { // to ensure people get kicked out of world foreach (var plr in w2.Players.Values) { plr.Client.Disconnect(); } })); } }
public Client(Account account, List <IPlugin> plugins) { Players = new Dictionary <int, PlayerData>(); _moveQueue = new Queue <MoveEvent>(); _net = new NetClient(); _account = account; _records = new List <MoveRecord>(); ApplyHooks(); // apply client hooks before plugin hooks (_plugins = plugins).ForEach(p => p.Instance(this)); _net.AddConnectionListener(Connected); _net.AddDisconnectListener(Disconnected); _watch = new Stopwatch(); _net.Connect(Reconnect = Servers.NameToRecon(account.Server)); NexusIp = Reconnect.Host; }
protected virtual void ErrorExtension_ConnectionError( object sender, string e) { // authentication failure if (string.Equals(e, "403::Handshake denied", StringComparison.OrdinalIgnoreCase) || string.Equals(e, "403:denied_by_security_policy:create_denied", StringComparison.OrdinalIgnoreCase) || string.Equals(e, "403::unknown client", StringComparison.OrdinalIgnoreCase) || string.Equals(e, "401::Authentication invalid", StringComparison.OrdinalIgnoreCase)) { _logger.LogWarning("Handled CometD Exception: {message}", e); // 1. Disconnect existing client. Disconnect(); // 2. Invalidate the access token. _tokenResponse.Invalidate(); _logger.LogDebug("Invalidate token for {name} ...", nameof(BayeuxClient)); // 3. Recreate BayeuxClient and populate it with a new transport with new security headers. CreateBayeuxClient(); // 4. Invoke the Reconnect Event Reconnect?.Invoke(this, true); } else if (e.Contains("you provided was invalid")) { var start = e.IndexOf('{'); var end = e.IndexOf('}'); var replayIdString = e.Substring(start + 1, end - (start + 1)); if (int.TryParse(replayIdString, out var replayId)) { InvalidReplayIdStrategy(replayId); } } else { _logger.LogError("{name} failed with the following message: {message}", nameof(ResilientStreamingClient), e); } }
static void Main(string[] args) { Reconnect reconnect = new Reconnect() { Host = "54.93.78.148", Port = 2050, GameId = -2, KeyTime = 0, Key = new byte[0] }; NetClient client = new NetClient(); client.Hook(PacketType.FAILURE, (p) => { Log.Error("Failure: " + ((FailurePacket)p).ErrorDescription); }); client.Hook(PacketType.MAPINFO, (p) => { LoadPacket load = new LoadPacket() { CharId = 2, IsFromArena = false }; client.SendPacket(load); }); client.Hook(PacketType.UPDATE, (p) => { client.SendPacket(new UpdateAckPacket()); }); client.Hook(PacketType.NEWTICK, (p) => { Log.Debug("NEW_TICK, id: " + ((NewTickPacket)p).TickId); }); HelloPacket hello = new HelloPacket() { BuildVersion = Constants.Game.Version, GameId = reconnect.GameId, Guid = RSA.Instance.Encrypt(""), Password = RSA.Instance.Encrypt(""), Secret = RSA.Instance.Encrypt(""), GameNet = "rotmg", PlayPlatform = "rotmg" }; client.Connect(reconnect); client.SendPacket(hello); Console.ReadKey(); }
private void HandleEvent(PubsubPayload evnt) { switch (evnt.Operation) { case PubsubOperation.Ping: SendHeartbeatAck(); Heartbeat?.Invoke(); break; case PubsubOperation.Pong: HeartbeatAck?.Invoke(); break; case PubsubOperation.Reconnect: Reconnect?.Invoke(); throw new TimeoutException("Server requested a reconnect"); case PubsubOperation.Message: HandleDispatchEvent(evnt); break; } }
public void Connect(Reconnect reconnect, string proxyHost = null, int proxyport = 0) { bool useProxy = (proxyHost != null && proxyport != 0); OnDisconnectHasBeenCalled = false; _incomingEncryption = new RC4(Utility.HexStringToBytes(IncomingKey)); _outgoingEncryption = new RC4(Utility.HexStringToBytes(OutgoingKey)); try { if (useProxy) { Log.Info("Connecting using HTTP proxy client..."); HttpProxyClient proxyClient = new HttpProxyClient(proxyHost, proxyport); TcpClient client = proxyClient.CreateConnection(reconnect.Host, reconnect.Port); _socket = client.Client; } else { Log.Info("Connecting no using proxy!"); _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); _socket.Connect(new IPEndPoint(IPAddress.Parse(reconnect.Host), reconnect.Port)); } _socket.NoDelay = true; _socket.ReceiveTimeout = 5000; _socket.SendTimeout = 5000; Disconnected = false; Start(); _onConnect?.Invoke(); } catch (Exception e) { Log.Error("Disconnecting due to error : " + e.Message); Disconnect(DisconnectReason.ExceptionOnConnection.SetDetails(e.Message)); } }
/// <summary> /// Http Post Handler. Handles http form inputs /// </summary> //[ServiceHandler(ServiceHandlerBehavior.Concurrent)] public IEnumerator<ITask> HttpPostHandler(HttpPost httpPost) { // Use helper to read form data ReadFormData readForm = new ReadFormData(httpPost); _httpUtilities.Post(readForm); // Read form data NameValueCollection parameters = null; yield return Arbiter.Choice(readForm.ResultPort, delegate(NameValueCollection p) { parameters = p; }, delegate(Exception e) { throw new Exception("Error reading form data", e); }); // Act on form data if (!string.IsNullOrEmpty(parameters["Action"]) && parameters["Action"] == "ScribblerConfig") { if (parameters["buttonOk"] == "Change" && _state.Connected) { SetNameBody newname = new SetNameBody(parameters["Name"]); SetName newnamemessage = new SetName(newname); _mainPort.PostUnknownType(newnamemessage); Activate( Arbiter.Choice( Arbiter.Receive<DefaultUpdateResponseType>(false, newnamemessage.ResponsePort, delegate(DefaultUpdateResponseType response) { HttpPostSuccess(httpPost); }), Arbiter.Receive<Fault>(false, newnamemessage.ResponsePort, delegate(Fault f) { HttpPostFailure(httpPost, f.Reason[0].Value); }) ) ); } else if (parameters["buttonOk"] == "Connect" && _state.Connected) { //close down this connection to make a new connection below PollTimer.Close(); System.Threading.Thread.Sleep(100); _scribblerCom.Close(); _state.Connected = false; //HttpPostSuccess(httpPost); } if (parameters["buttonOk"] == "Connect" && !_state.Connected) { int port = 0; int.TryParse(parameters["ComPort"], out port); string name = parameters["Name"]; if (!string.IsNullOrEmpty(name) && name.Length > 8) name = name.Substring(0, 8); _state.ComPort = port; _state.RobotName = name; //open Scribbler Communications port LogInfo("connecting to scribbler..."); Reconnect rec = new Reconnect(); _mainPort.PostUnknownType(rec); yield return Arbiter.Choice(rec.ResponsePort, delegate(DefaultUpdateResponseType r) { LogInfo("connected, sending http reply"); HttpPostSuccess(httpPost); LogInfo("http reply sent"); }, delegate(Fault f) { httpPost.ResponsePort.Post(f); }); } } else if (!string.IsNullOrEmpty(parameters["Action"]) && parameters["Action"] == "ScribblerSensors") { if (parameters["buttonOk"] == "Poll" && _state.Connected) { ScribblerCommand cmd = new ScribblerCommand(ScribblerHelper.Commands.GET_ALL); SendScribblerCommand sendcmd = new SendScribblerCommand(cmd); _scribblerComPort.Post(sendcmd); Activate( Arbiter.Choice( Arbiter.Receive<ScribblerResponse>(false, sendcmd.ResponsePort, delegate(ScribblerResponse response) { HttpPostSuccess(httpPost); }), Arbiter.Receive<Fault>(false, sendcmd.ResponsePort, delegate(Fault f) { HttpPostFailure(httpPost, f.Reason[0].Value); }) ) ); } } else if (!string.IsNullOrEmpty(parameters["Action"]) && parameters["Action"] == "ScribblerMotors") { if (parameters["buttonOk"] == "Set" && _state.Connected) { int left = _state.MotorLeft; int right = _state.MotorRight; int.TryParse(parameters["LeftMotor"], out left); int.TryParse(parameters["RightMotor"], out right); SetMotorsBody setMotorsBody = new SetMotorsBody(left, right); SetMotors setMotorsRequest = new SetMotors(setMotorsBody); _mainPort.PostUnknownType(setMotorsRequest); Activate( Arbiter.Choice( Arbiter.Receive<DefaultUpdateResponseType>(false, setMotorsRequest.ResponsePort, delegate(DefaultUpdateResponseType response) { HttpPostSuccess(httpPost); }), Arbiter.Receive<Fault>(false, setMotorsRequest.ResponsePort, delegate(Fault f) { HttpPostFailure(httpPost, f.Reason[0].Value); }) ) ); } else if (parameters["buttonOk"] == "All Stop" && _state.Connected) { SetMotorsBody setMotorsBody = new SetMotorsBody(100, 100); SetMotors setMotorsRequest = new SetMotors(setMotorsBody); _mainPort.PostUnknownType(setMotorsRequest); Activate( Arbiter.Choice( Arbiter.Receive<DefaultUpdateResponseType>(false, setMotorsRequest.ResponsePort, delegate(DefaultUpdateResponseType response) { HttpPostSuccess(httpPost); }), Arbiter.Receive<Fault>(false, setMotorsRequest.ResponsePort, delegate(Fault f) { HttpPostFailure(httpPost, f.Reason[0].Value); }) ) ); } } else if (!string.IsNullOrEmpty(parameters["Action"]) && parameters["Action"] == "ScribblerLEDs") { if (parameters["buttonOk"] == "Set" && _state.Connected) { bool left = ((parameters["LeftLED"] ?? "off") == "on"); bool center = ((parameters["CenterLED"] ?? "off") == "on"); bool right = ((parameters["RightLED"] ?? "off") == "on"); SetAllLedsBody leds = new SetAllLedsBody(left, center, right); SetAllLEDs setAllLeds = new SetAllLEDs(leds); _mainPort.PostUnknownType(setAllLeds); Activate( Arbiter.Choice( Arbiter.Receive<DefaultUpdateResponseType>(false, setAllLeds.ResponsePort, delegate(DefaultUpdateResponseType response) { HttpPostSuccess(httpPost); }), Arbiter.Receive<Fault>(false, setAllLeds.ResponsePort, delegate(Fault f) { HttpPostFailure(httpPost, f.Reason[0].Value); }) ) ); } } else if (!string.IsNullOrEmpty(parameters["Action"]) && parameters["Action"] == "ScribblerSpeaker") { if (parameters["buttonOk"] == "Play" && _state.Connected) { int tone1 = 0; int tone2 = 0; int duration = 0; int.TryParse(parameters["Tone1"], out tone1); int.TryParse(parameters["Tone2"], out tone2); int.TryParse(parameters["Duration"], out duration); PlayToneBody playTone = new PlayToneBody(duration, tone1, tone2); PlayTone playToneMessage = new PlayTone(playTone); _mainPort.PostUnknownType(playToneMessage); Activate( Arbiter.Choice( Arbiter.Receive<DefaultUpdateResponseType>(false, playToneMessage.ResponsePort, delegate(DefaultUpdateResponseType response) { HttpPostSuccess(httpPost); }), Arbiter.Receive<Fault>(false, playToneMessage.ResponsePort, delegate(Fault f) { HttpPostFailure(httpPost, f.Reason[0].Value); }) ) ); } } else { HttpPostFailure(httpPost, "Unknown Http Post"); } yield break; }
private async Task <Packet> ProcessPacket(byte[] data) { string str = Encoding.UTF8.GetString(data); if (Regex.IsMatch(str, "^GET")) { requestHeader = new RequestHeader(str); requestHeader.resource = requestHeader.resource.Replace("/csf-websocket-url", ""); Logger.Info($"Requesting resource: {requestHeader.resource}"); string ip1 = tcpclient.Client.RemoteEndPoint.ToString(); string[] ip_parts = ip1.Split("."); Logger.Info($"IP: {ip1}"); Logger.Debug($"Recieved header: {str}"); if (ip_parts[0] != "172" && ip_parts[0] != "127") { ResponseHeader respheader = new ResponseHeader { responseCode = HttpCodes.OK }; await Send(respheader); await Send("Hello World!"); stillOk = false; } else if (requestHeader.parameters.ContainsKey("Sec-WebSocket-Key")) { ResponseHeader respheader = new ResponseHeader { responseCode = HttpCodes.SwitchingProtocols }; respheader.parameters["Server"] = "CSF-Websocket"; respheader.parameters["Connection"] = "Upgrade"; respheader.parameters["Upgrade"] = "websocket"; respheader.parameters["Sec-WebSocket-Accept"] = GenerateSecWebSocketKey(requestHeader.parameters["Sec-WebSocket-Key"]); try { if (requestHeader.parameters.ContainsKey("Sec-WebSocket-Extensions")) { Logger.Info($"Supported extensions: {requestHeader.parameters["Sec-WebSocket-Extensions"]}"); Chiper = StreamCipher.Factory(requestHeader.parameters["Sec-WebSocket-Extensions"]); } else { Chiper = StreamCipher.Factory("permessage-deflate"); } if (requestHeader.parameters.ContainsKey("Sec-WebSocket-Protocol")) { string[] options = requestHeader.parameters["Sec-WebSocket-Protocol"].Split(","); foreach (string option_raw in options) { string option = option_raw.Trim(); if (option.Contains("csf-socket-")) { respheader.parameters["Sec-WebSocket-Protocol"] = option; } } } await Send(respheader); await SendHello(); } catch (UnsupportedExtension) { ResponseHeader invext = new ResponseHeader { responseCode = HttpCodes.NotAcceptable }; await Send(invext); await Send("The requested websokcet extension is not supported"); stillOk = false; } } else { ResponseHeader respheader = new ResponseHeader { responseCode = HttpCodes.UpgradeRequired }; await Send(respheader); await Send("This is not a website! Upgrade your connection to WebSocket"); stillOk = false; } } else { WsPacket WebSocketPacket = Chiper.Decode(data); OpCode opcode = WebSocketPacket.GetOpCode(); if (opcode == OpCode.TextFrame) { string pstr = WebSocketPacket.GetPayload(); try { Packet p = new Packet(pstr); PacketType type = p.GetPacketType(); if (type == PacketType.Heartbeat) { HeartBeatNow(); Packet ack = new Packet(PacketType.HeartbeatACK); await Send(ack); return(null); } else if (type == PacketType.Reconnect) { Reconnect rp = p.GetPacketData <Reconnect>(); if (UsedSessions.Contains(rp.session_id)) { this.session = rp.session_id; await SendHello(); } else { Packet invsess = new Packet(PacketType.InvalidSession); await Send(invsess); stillOk = false; } return(null); } else if (type == PacketType.Identify) { identity = p.GetPacketData <Identity>(); } else { if (identity == null) { stillOk = false; return(null); } } return(p); } catch (Exception e) { Logger.Error($"Packet conversion error: {e.Message}"); Logger.Error($"Receied data: {string.Join(" ", data)}"); Logger.Error($"Decoded: {pstr}"); Logger.Error($"{e.StackTrace}"); } } else if (opcode == OpCode.Ping) { Logger.Debug("Ping Pong"); WsPacket pong = new WsPacket(OpCode.Pong); await Send(pong); } } return(null); }
private void OnLoaded(object sender, RoutedEventArgs e) { Reconnect.Focus(); }
public NetClient(Reconnect reconnect) => Connect(reconnect);
internal void OnReconnect(object t, EventArgs e) { Reconnect?.Invoke(t, e); }
private IEnumerator<ITask> ReconnectHandler(Reconnect req) { //try //{ _state.Connected = false; //look for scribbler on last known Com port if (_state.ComPort > 0) { var rPort = new Port<EmptyValue>(); Exception ex = null; new Thread(new ThreadStart(delegate() { try { _scribblerCom.Open(_state.ComPort); } catch (Exception e) { ex = e; } rPort.Post(new EmptyValue()); })).Start(); yield return Arbiter.Receive(false, rPort, delegate(EmptyValue v) { }); if (ex != null) { req.ResponsePort.Post(RSUtils.FaultOfException(ex)); yield break; } _state.RobotName = _scribblerCom.foundRobotName; _state.ComPort = _scribblerCom.openedComPort; LogInfo(LogGroups.Console, "Now connected to robot \"" + _state.RobotName + "\" on COM" + _state.ComPort); SaveState(_state); PollTimer = new System.Timers.Timer(); PollTimer.Interval = TimerDelay; PollTimer.AutoReset = true; PollTimer.Elapsed += new System.Timers.ElapsedEventHandler(PollTimer_Elapsed); //PollTimer.Start(); //fix state _state.MotorLeft = 100; _state.MotorRight = 100; _state.LEDLeft = false; _state.LEDRight = false; _state.LEDCenter = false; _state.Connected = true; //play startup tone LogInfo("playing startup tone..."); PlayTone startTone = new PlayTone(new PlayToneBody(.2, 1000, 2000)); _mainPort.PostUnknownType(startTone); //yield return Arbiter.Choice(startTone.ResponsePort, // delegate(DefaultUpdateResponseType r) { }, // delegate(Fault f) { throw new Exception("Could not play startup tone"); }); LogInfo("done playing"); req.ResponsePort.Post(DefaultUpdateResponseType.Instance); LogInfo("reconnect sent success"); } else { req.ResponsePort.Post(RSUtils.FaultOfException(new ScribblerBadCOMPortException())); LogInfo("reconnect sent failure"); } yield break; }
void ProcessMessage(IrcMessage message) { if (message.Command == $":{message.Source}" && message.Arguments.Length > 0) { // twitch seems to have issues building proper irc messages ProcessMessage(new IrcMessage(message.Arguments[0], message.Arguments.Skip(1).ToArray())); return; } string channelname; switch (message.Command) { case "CAP": if (message.Arguments.Length < 3) { break; } if (message.Arguments[1] == "ACK") { CapAcknowledged?.Invoke(message.Arguments[2]); } break; case "PING": SendMessage(new IrcMessage("PONG", message.Arguments)); break; case "JOIN": channelname = GetChannelName(message.Arguments[0]); if (message.ExtractUser().ToLower() == user.ToLower()) { JoinChannel(channelname); } SendChannelMessage(channelname, message); break; case "PART": channelname = GetChannelName(message.Arguments[0]); SendChannelMessage(channelname, message); if (message.ExtractUser().ToLower() == user.ToLower()) { ChatChannel channel; lock (channellock) { if (channels.TryGetValue(channelname, out channel)) { channels.Remove(channelname); } } if (channel != null) { ChannelLeft?.Invoke(channel); } } break; case "tmi.twitch.tv RECONNECT": case "RECONNECT": Reconnect?.Invoke(); break; case "001": case "002": case "003": case "004": // connection success break; case "372": case "375": // message of the day break; case "376": connectionwait.Set(); // end of message of the day break; case "353": GetChannel(message.Arguments[2])?.OnMessage(message); break; case "366": GetChannel(message.Arguments[1])?.OnMessage(message); break; case "ROOMSTATE": case "PRIVMSG": case "USERNOTICE": case "NOTICE": case "USERSTATE": SendChannelMessage(message.Arguments[0], message); break; case "HOSTTARGET": if (!message.Arguments[1].StartsWith("-")) { TrySendChannelMessage(message.Arguments[0], message); TrySendChannelMessage(message.Arguments[1].Split(' ')[0], message); } break; case "MODE": // channel or user mode ... not that important for now break; default: Logger.Warning(this, "Unprocessed message", message.ToString()); break; } }