Skip to content

Commit

Permalink
Issue: #57
Browse files Browse the repository at this point in the history
Added handler when we send ALMOST anything to the server.
  • Loading branch information
xforever1313 committed Nov 1, 2020
1 parent 71975cd commit 07b2386
Show file tree
Hide file tree
Showing 9 changed files with 594 additions and 47 deletions.
172 changes: 172 additions & 0 deletions Chaskis/ChaskisCore/Handlers/Send/SendEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//
// Copyright Seth Hendrick 2020.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.NetworkInformation;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using SethCS.Exceptions;
using SethCS.Extensions;

namespace Chaskis.Core
{
/// <summary>
/// Args that are passed into <see cref="SendEventHandler"/> when
/// *any* command is sent to the server.
/// </summary>
public sealed class SendEventArgs : BaseCoreEventArgs
{
// ---------------- Fields ----------------

internal const string XmlRootName = "chaskis_send_event";

// ---------------- Constructor ----------------

internal SendEventArgs() :
base()
{
this.Command = null;
}

// ---------------- Properties ----------------

public IIrcWriter Writer { get; internal set; }

/// <summary>
/// The IRC command sent to the server.
/// </summary>
public string Command { get; internal set; }

protected override string XmlElementName => XmlRootName;

protected override IEnumerable<XElement> ChildToXml()
{
// It is possible for a character to not be a valid XML
// character since we can send bytes with some commands (such as CTCP Ping).
// So, we need to escape these characters, while still making them
// readable in the log. We will do that by
// replacing them with [hexValue] in the XML, then
// putting them back on the otherside.
bool escaped = false;
StringBuilder builder = new StringBuilder();
foreach( char c in this.Command )
{
if(
( XmlConvert.IsXmlChar( c ) == false ) ||
( c == '[' ) ||
( c == ']' )
)
{
escaped = true;
builder.Append( $"[{Convert.ToInt32( c ):X}]" );
}
else
{
builder.Append( c );
}
}

XElement commandElement = new XElement( "command", builder );
commandElement.Add( new XAttribute( "escaped", escaped ) );
return new List<XElement>
{
commandElement
};
}
}

/// <summary>
/// Extensions to <see cref="SendEventArgs"/>
/// </summary>
internal static class SendEventArgsExtensions
{
public static SendEventArgs FromXml( string xmlString, IIrcWriter writer )
{
SendEventArgs args = new SendEventArgs
{
Writer = writer
};

XElement root = BaseCoreEventArgs.ParseXml( args, xmlString );
BaseCoreEventArgs.ParseBaseXml( args, root );

foreach( XElement child in root.Elements() )
{
if( "command".EqualsIgnoreCase( child.Name.LocalName ) )
{
// Assume true, we don't want things to crash if this
// was somehow false.
bool escaped = true;
foreach( XAttribute attr in child.Attributes() )
{
if( "escaped".EqualsIgnoreCase( attr.Name.LocalName ) )
{
if( bool.TryParse( attr.Value, out escaped ) == false )
{
escaped = false;
}
}
}

// If we did not escape, just assign the value,
// no need to over-complciate things.
if( escaped == false )
{
args.Command = child.Value;
}
else
{
args.Command = ParseCommand( child.Value );
}
}
}

if( args.Command == null )
{
throw new ValidationException(
$"Could not find all required properties when creating {nameof( SendEventArgs )}"
);
}

return args;
}

private static string ParseCommand( string originalCommand )
{
StringBuilder builder = new StringBuilder();

bool parse = false;
StringBuilder parser = new StringBuilder();
foreach( char c in originalCommand )
{
if( c == '[' )
{
parse = true;
}
else if( c == ']' )
{
parse = false;
builder.Append( Convert.ToChar( int.Parse( parser.ToString(), NumberStyles.HexNumber ) ) );
parser.Clear();
}
else if( parse )
{
parser.Append( c );
}
else
{
builder.Append( c );
}
}

return builder.ToString();
}
}
}
37 changes: 37 additions & 0 deletions Chaskis/ChaskisCore/Handlers/Send/SendEventConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Copyright Seth Hendrick 2020.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

using System.Collections.Generic;

namespace Chaskis.Core
{
/// <summary>
/// Event to configure <see cref="SendEventHandler"/>
/// </summary>
public sealed class SendEventConfig :
BaseCoreEvent<SendEventConfig, SendHandlerAction, SendEventArgs>
{
// ---------------- Constructor ----------------

public SendEventConfig()
{
}

// ---------------- Functions ----------------

public override SendEventConfig Clone()
{
return (SendEventConfig)this.MemberwiseClone();
}

protected override IEnumerable<string> ValidateChild()
{
// Nothing to validate.
return null;
}
}
}
43 changes: 43 additions & 0 deletions Chaskis/ChaskisCore/Handlers/Send/SendEventHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Copyright Seth Hendrick 2020.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

using System.Text.RegularExpressions;

namespace Chaskis.Core
{
public delegate void SendHandlerAction( SendEventArgs args );

/// <summary>
/// Event that gets fired when the bot sends ALMOST ANYTHING to the server.
/// This means while you could use this to capture, say us sending a join command to the server,
/// you're better off using <see cref="SendJoinEventHandler"/>.
/// </summary>
public sealed class SendEventHandler : BaseCoreEventHandler<SendEventConfig>
{
// ---------------- Fields ----------------

public static readonly Regex Regex = new Regex(
$@"^<{SendEventArgs.XmlRootName}>.+</{SendEventArgs.XmlRootName}>",
RegexOptions.ExplicitCapture | RegexOptions.Compiled | RegexOptions.IgnoreCase
);

// ---------------- Constructor ----------------

public SendEventHandler( SendEventConfig config ) :
base( config, Regex )
{
}

// ---------------- Functions ----------------

protected override void HandleEventInternal( HandlerArgs args, Match match )
{
SendEventArgs connectionArgs = SendEventArgsExtensions.FromXml( args.Line, args.IrcWriter );
this.config.LineAction( connectionArgs );
}
}
}
35 changes: 17 additions & 18 deletions Chaskis/ChaskisCore/IrcConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,24 +433,9 @@ private void SendMessageInternal( string msg, string channel, string prefix, str
/// </summary>
private void SendMessageHelper( string line, string channel, string msgType )
{
this.AddToWriterQueue(
delegate ()
{
lock( this.ircWriterLock )
{
// This should be in the lock. If this is before the lock,
// IsConnected can return true, this thread can be preempted,
// and a thread that disconnects the connection runs. Now, when this thread runs again, we try to write
// to a socket that is closed which is a problem.
if( this.connection.IsConnected == false )
{
return;
}

// PRIVMSG < msgtarget > < message >
this.connection.WriteLine( $"{msgType} {channel} :{line}" );
}
}
// PRIVMSG < msgtarget > < message >
this.SendRawCmd(
$"{msgType} {channel} :{line}"
);
}

Expand Down Expand Up @@ -573,11 +558,25 @@ public void SendRawCmd( string cmd )
);
}

this.OnReadLine(
new SendEventArgs
{
Command = cmd,
Protocol = ChaskisEventProtocol.IRC,
Server = this.Config.Server,
Writer = this
}.ToXml()
);

this.AddToWriterQueue(
delegate ()
{
lock( this.ircWriterLock )
{
// This should be in the lock. If this is before the lock,
// IsConnected can return true, this thread can be preempted,
// and a thread that disconnects the connection runs. Now, when this thread runs again, we try to write
// to a socket that is closed which is a problem.
if( this.connection.IsConnected == false )
{
return;
Expand Down
20 changes: 0 additions & 20 deletions Chaskis/ChaskisCore/Regexes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,5 @@ public static class Regexes
@"^:(((?<nickOrServer>\S+)!(?<username>\S+)@(?<host>\S+))|" + // All three nick, user, and host.
@"((?<nickOrServer>\S+)@(?<host>\S+))|"+ // Just nick and host.
@"((?<nickOrServer>\S+)))"; // Just nick or server.

/// <summary>
/// Pattern that can be used to capture Chaskis
/// IRC connect events.
/// Groups:
/// server - the Server we connected to
/// nick - The user name we connected as.
/// </summary>
public static readonly string ChaskisIrcConnectEvent =
@"CONNECT\s+TO\s+(?<server>\S+)\s+AS\s+(?<nick>\S+)";

/// <summary>
/// Pattern that can be used to capture Chaskis
/// IRC disconnect events.
/// Groups:
/// server - the Server we disconnected from
/// nick - The user name we disconnected as.
/// </summary>
public static readonly string ChaskisIrcDisconnectEvent =
@"DISCONNECT\s+FROM\s+(?<server>\S+)\s+AS\s+(?<nick>\S+)";
}
}
38 changes: 29 additions & 9 deletions Chaskis/Plugins/ConsoleOut/ConsoleOut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,28 @@ public string About
/// <param name="pluginInit">The class that has information required for initing the plugin.</param>
public void Init( PluginInitor initor )
{
AllHandlerConfig allHandlerConfig = new AllHandlerConfig
{
AllAction = delegate ( AllHandlerArgs args )
AllHandlerConfig allHandlerConfig = new AllHandlerConfig
{
Console.WriteLine( args.Line );
}
};
AllAction = LineAction
};

AllHandler handler = new AllHandler(
allHandlerConfig
);
AllHandler handler = new AllHandler(
allHandlerConfig
);

this.handlers.Add( handler );
this.handlers.Add( handler );
}

{
SendEventConfig onSendConfig = new SendEventConfig
{
LineAction = LineAction
};

SendEventHandler handler = new SendEventHandler( onSendConfig );
this.handlers.Add( handler );
}
}

/// <summary>
Expand All @@ -120,5 +129,16 @@ public void Dispose()
{
// Nothing to dispose.
}

private static void LineAction( AllHandlerArgs args )
{

Console.WriteLine( args.Line );
}

private static void LineAction( SendEventArgs args )
{
Console.WriteLine( args.Command );
}
}
}
Loading

0 comments on commit 07b2386

Please sign in to comment.