Browse Source

Added Module loading and running.

Added command parsing to bot.
Added initial PingMe module as POC.
master
Teknikode 7 years ago
parent
commit
f2b81f19b8
  1. 58
      Combot/Bot.cs
  2. 7
      Combot/Combot.csproj
  3. 22
      Combot/Command.cs
  4. 52
      Combot/Configurations/ServerConfig.cs
  5. 68
      Combot/Modules/Command.cs
  6. 37
      Combot/Modules/CommandArgument.cs
  7. 24
      Combot/Modules/CommandMessage.cs
  8. 81
      Combot/Modules/Module.cs
  9. 29
      Combot/Modules/ModuleClasses/PingMe.cs
  10. 28
      Combot/Modules/Option.cs
  11. 4
      IRCServices/IRC.cs
  12. 10
      IRCServices/Messaging/MessageTypes.cs
  13. 57
      IRCServices/Messaging/Messages.cs
  14. 15
      IRCServices/Nick.cs
  15. 17
      Interface/ViewModels/MainViewModel.cs

58
Combot/Bot.cs

@ -3,27 +3,37 @@ using System.Collections.Generic; @@ -3,27 +3,37 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using Combot.IRCServices;
using Combot.Configurations;
using Combot.IRCServices.Messaging;
using Combot.Modules;
using Module = Combot.Modules.Module;
namespace Combot
{
public class Bot
{
public event Action<CommandMessage> CommandReceivedEvent;
public event Action<BotError> ErrorEvent;
public ServerConfig ServerConfig;
public IRC IRC;
public bool Connected = false;
private List<Module> _Modules;
public Bot(ServerConfig serverConfig)
{
IRC = new IRC();
_Modules = new List<Module>();
ServerConfig = serverConfig;
IRC.ConnectEvent += HandleConnectEvent;
IRC.DisconnectEvent += HandleDisconnectEvent;
IRC.Message.ServerReplyEvent += HandleReplyEvent;
IRC.Message.ChannelMessageReceivedEvent += HandleChannelMessageReceivedEvent;
LoadModules();
}
/// <summary>
@ -70,6 +80,21 @@ namespace Combot @@ -70,6 +80,21 @@ namespace Combot
Connected = false;
}
public void LoadModules()
{
foreach (Module module in ServerConfig.Modules)
{
if (module.Enabled && !_Modules.Exists(mod => mod.ClassName == module.ClassName))
{
Module loadedModule = module.CreateInstance(this);
if (loadedModule.Loaded)
{
_Modules.Add(loadedModule);
}
}
}
}
private void HandleConnectEvent()
{
Connected = true;
@ -95,5 +120,38 @@ namespace Combot @@ -95,5 +120,38 @@ namespace Combot
}
}
}
private void HandleChannelMessageReceivedEvent(object sender, ChannelMessage e)
{
// The message was a command
if (e.Message.StartsWith(ServerConfig.CommandPrefix))
{
string[] msgArgs = e.Message.Split(new char[] {' '}, 2, StringSplitOptions.RemoveEmptyEntries);
string command = msgArgs[0].Remove(0, ServerConfig.CommandPrefix.Length);
List<string> argsOnly = msgArgs.ToList();
argsOnly.RemoveAt(0);
if (_Modules.Exists(module => module.Commands.Exists(cmd => cmd.Triggers.Contains(command)) && module.Loaded))
{
CommandMessage newCommand = new CommandMessage();
newCommand.Nick.Copy(e.Sender);
IRC.Channels.ForEach(channel => channel.Nicks.ForEach(nick =>
{
if (nick.Nickname == newCommand.Nick.Nickname)
{
newCommand.Nick.AddPrivileges(nick.Privileges);
}
}));
newCommand.TimeStamp = e.TimeStamp;
newCommand.ModuleName =_Modules.Find(module => module.Commands.Exists(cmd => cmd.Triggers.Contains(command)) && module.Loaded).Name;
newCommand.Command = command;
newCommand.Arguments.AddRange(argsOnly);
if (CommandReceivedEvent != null)
{
CommandReceivedEvent(newCommand);
}
}
}
}
}
}

7
Combot/Combot.csproj

@ -59,13 +59,17 @@ @@ -59,13 +59,17 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Bot.cs" />
<Compile Include="Command.cs" />
<Compile Include="Modules\Command.cs" />
<Compile Include="Configurations\ChannelConfig.cs" />
<Compile Include="Configurations\Config.cs" />
<Compile Include="Configurations\HostConfig.cs" />
<Compile Include="Configurations\JsonHelper.cs" />
<Compile Include="Configurations\ServerConfig.cs" />
<Compile Include="Help.cs" />
<Compile Include="Modules\CommandArgument.cs" />
<Compile Include="Modules\CommandMessage.cs" />
<Compile Include="Modules\ModuleClasses\PingMe.cs" />
<Compile Include="Modules\Option.cs" />
<Compile Include="Types.cs" />
<Compile Include="Methods.cs" />
<Compile Include="Modules\Module.cs" />
@ -101,6 +105,7 @@ @@ -101,6 +105,7 @@
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

22
Combot/Command.cs

@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Combot
{
public class Command
{
public string Name { get; set; }
public string Value { get; set; }
public List<CommandArgument> Arguments { get; set; }
}
public class CommandArgument
{
public string Name { get; set; }
public string Value { get; set; }
public bool Required { get; set; }
}
}

52
Combot/Configurations/ServerConfig.cs

@ -4,6 +4,7 @@ using System.Linq; @@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Net;
using System.Threading.Tasks;
using Combot.Modules;
namespace Combot.Configurations
{
@ -12,9 +13,16 @@ namespace Combot.Configurations @@ -12,9 +13,16 @@ namespace Combot.Configurations
public event Action ModifyEvent;
public ServerConfig()
{
SetDefaults();
}
public void SetDefaults()
{
AutoConnect = false;
CommandPrefix = string.Empty;
Channels = new List<ChannelConfig>();
Modules = new List<Module>();
Hosts = new List<HostConfig>();
Nickname = string.Empty;
Realname = string.Empty;
@ -97,6 +105,40 @@ namespace Combot.Configurations @@ -97,6 +105,40 @@ namespace Combot.Configurations
}
}
private string _CommandPrefix;
public string CommandPrefix
{
get
{
return _CommandPrefix;
}
set
{
if (_CommandPrefix != value)
{
_CommandPrefix = value;
}
}
}
private bool _AutoConnect;
public bool AutoConnect
{
get
{
return _AutoConnect;
}
set
{
if (_AutoConnect != value)
{
_AutoConnect = value;
}
}
}
private List<HostConfig> _Hosts;
public List<HostConfig> Hosts
{
@ -131,19 +173,19 @@ namespace Combot.Configurations @@ -131,19 +173,19 @@ namespace Combot.Configurations
}
}
private bool _AutoConnect;
public bool AutoConnect
private List<Module> _Modules;
public List<Module> Modules
{
get
{
return _AutoConnect;
return _Modules;
}
set
{
if (_AutoConnect != value)
if (_Modules != value)
{
_AutoConnect = value;
_Modules = value;
}
}
}

68
Combot/Modules/Command.cs

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
using System.Collections.Generic;
namespace Combot.Modules
{
public class Command
{
public string Name { get; set; }
public string Description { get; set; }
public List<string> Triggers { get; set; }
public List<string> ChannelBlacklist { get; set; }
public List<string> NickBlacklist { get; set; }
public List<CommandArgument> Arguments { get; set; }
public bool ShowHelp { get; set; }
public bool SpamCheck { get; set; }
public bool ShouldSerializeValue()
{
return false;
}
public Command()
{
SetDefaults();
}
public void SetDefaults()
{
Name = string.Empty;
Description = string.Empty;
Triggers = new List<string>();
ChannelBlacklist = new List<string>();
NickBlacklist = new List<string>();
Arguments = new List<CommandArgument>();
ShowHelp = true;
SpamCheck = true;
}
public void Copy(Command command)
{
Name = command.Name;
Description = command.Description;
Triggers = new List<string>();
foreach (string trigger in command.Triggers)
{
Triggers.Add(trigger);
}
ChannelBlacklist = new List<string>();
foreach (string channel in command.ChannelBlacklist)
{
ChannelBlacklist.Add(channel);
}
NickBlacklist = new List<string>();
foreach (string nick in command.NickBlacklist)
{
NickBlacklist.Add(nick);
}
Arguments = new List<CommandArgument>();
foreach (CommandArgument arg in command.Arguments)
{
CommandArgument newArg = new CommandArgument();
newArg.Copy(arg);
Arguments.Add(newArg);
}
ShowHelp = command.ShowHelp;
SpamCheck = command.SpamCheck;
}
}
}

37
Combot/Modules/CommandArgument.cs

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
using System.Collections.Generic;
namespace Combot.Modules
{
public class CommandArgument
{
public string Name { get; set; }
public string Description { get; set; }
public List<string> Triggers { get; set; }
public bool Required { get; set; }
public CommandArgument()
{
SetDefaults();
}
public void SetDefaults()
{
Name = string.Empty;
Description = string.Empty;
Triggers = new List<string>();
Required = false;
}
public void Copy(CommandArgument argument)
{
Name = argument.Name;
Description = argument.Description;
Triggers = new List<string>();
foreach (string trigger in argument.Triggers)
{
Triggers.Add(trigger);
}
Required = argument.Required;
}
}
}

24
Combot/Modules/CommandMessage.cs

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using Combot.IRCServices;
namespace Combot.Modules
{
public class CommandMessage
{
public Nick Nick { get; set; }
public DateTime TimeStamp { get; set; }
public string ModuleName { get; set; }
public string Command { get; set; }
public List<string> Arguments { get; set; }
public CommandMessage()
{
Nick = new Nick();
TimeStamp = DateTime.Now;
ModuleName = string.Empty;
Command = string.Empty;
Arguments = new List<string>();
}
}
}

81
Combot/Modules/Module.cs

@ -3,13 +3,88 @@ using System.Collections.Generic; @@ -3,13 +3,88 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace Combot.Modules
{
abstract internal class Module
public class Module
{
abstract public List<Command> Commands { get; set; }
public string Name { get; set; }
public string ClassName { get; set; }
public bool Enabled { get; set; }
public List<Command> Commands { get; set; }
public List<Option> Options { get; set; }
abstract internal void Initialize() { }
public bool Loaded { get; set; }
public bool ShouldSerializeLoaded()
{
return false;
}
protected Bot Bot;
public Module()
{
SetDefaults();
}
virtual public void Initialize() { }
virtual public void HandleCommandEvent(CommandMessage command) { }
public void SetDefaults()
{
Name = string.Empty;
ClassName = string.Empty;
Enabled = false;
Loaded = false;
Commands = new List<Command>();
Options = new List<Option>();
}
public void Copy(Module module)
{
Name = module.Name;
ClassName = module.ClassName;
Enabled = module.Enabled;
Commands = new List<Command>();
foreach (Command command in module.Commands)
{
Command newCommand = new Command();
newCommand.Copy(command);
Commands.Add(newCommand);
}
Options = new List<Option>();
foreach (Option option in module.Options)
{
Option newOption = new Option();
newOption.Copy(option);
Options.Add(newOption);
}
}
public Module CreateInstance(Bot bot)
{
Module newModule = new Module();
if (!Loaded)
{
//create the class base on string
//note : include the namespace and class name (namespace=Bot.Modules, class name=<class_name>)
Assembly a = Assembly.Load("Combot");
Type t = a.GetType("Combot.Modules.ModuleClasses." + ClassName);
//check to see if the class is instantiated or not
if (t != null)
{
newModule = (Module)Activator.CreateInstance(t);
newModule.Copy(this);
newModule.Loaded = true;
newModule.Bot = bot;
newModule.Initialize();
}
}
return newModule;
}
}
}

29
Combot/Modules/ModuleClasses/PingMe.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using Combot.IRCServices;
using Combot.IRCServices.Messaging;
namespace Combot.Modules.ModuleClasses
{
public class PingMe : Module
{
private List<Dictionary<Nick, DateTime>> pingList;
public override void Initialize()
{
pingList = new List<Dictionary<Nick, DateTime>>();
Bot.IRC.Message.CTCPMessageRecievedEvent += HandlePingResponse;
Bot.CommandReceivedEvent += HandleCommandEvent;
}
public override void HandleCommandEvent(CommandMessage command)
{
}
private void HandlePingResponse(object sender, CTCPMessage e)
{
}
}
}

28
Combot/Modules/Option.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
namespace Combot.Modules
{
public class Option
{
public string Name { get; set; }
public string Description { get; set; }
public dynamic Value { get; set; }
public Option()
{
SetDefaults();
}
public void SetDefaults()
{
Name = string.Empty;
Description = string.Empty;
Value = null;
}
public void Copy(Option option)
{
Name = option.Name;
Description = option.Description;
Value = option.Value;
}
}
}

4
IRCServices/IRC.cs

@ -20,10 +20,10 @@ namespace Combot.IRCServices @@ -20,10 +20,10 @@ namespace Combot.IRCServices
public string Nickname { get; set; }
public Dictionary<string, PrivilegeMode> PrivilegeMapping = new Dictionary<string, PrivilegeMode>() { { "+", PrivilegeMode.v }, { "%", PrivilegeMode.h }, { "@", PrivilegeMode.o }, { "&", PrivilegeMode.a }, { "~", PrivilegeMode.q } };
private TCPInterface _TCP;
private Thread TCPReader;
private event Action<string> TCPMessageEvent;
private ReaderWriterLockSlim ChannelRWLock;
private readonly TCPInterface _TCP;
private readonly ReaderWriterLockSlim ChannelRWLock;
public IRC()
{

10
IRCServices/Messaging/MessageTypes.cs

@ -1,8 +1,5 @@ @@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Combot.IRCServices.Messaging
{
@ -62,6 +59,13 @@ namespace Combot.IRCServices.Messaging @@ -62,6 +59,13 @@ namespace Combot.IRCServices.Messaging
public string Message { get; set; }
}
public class CTCPMessage : IMessage
{
public Nick Target { get; set; }
public string Command { get; set; }
public string Arguments { get; set; }
}
public class TopicChangeInfo : IMessage
{
public string Channel { get; set; }

57
IRCServices/Messaging/Messages.cs

@ -17,6 +17,7 @@ namespace Combot.IRCServices.Messaging @@ -17,6 +17,7 @@ namespace Combot.IRCServices.Messaging
public event EventHandler<ServerNotice> ServerNoticeReceivedEvent;
public event EventHandler<ChannelNotice> ChannelNoticeReceivedEvent;
public event EventHandler<PrivateNotice> PrivateNoticeReceivedEvent;
public event EventHandler<CTCPMessage> CTCPMessageRecievedEvent;
public event EventHandler<TopicChangeInfo> TopicChangeEvent;
public event EventHandler<ChannelModeChangeInfo> ChannelModeChangeEvent;
public event EventHandler<UserModeChangeInfo> UserModeChangeEvent;
@ -48,6 +49,7 @@ namespace Combot.IRCServices.Messaging @@ -48,6 +49,7 @@ namespace Combot.IRCServices.Messaging
Regex pingRegex = new Regex(@"^PING :(?<Message>.+)", RegexOptions.None);
Regex pongRegex = new Regex(@"^PONG :(?<Message>.+)", RegexOptions.None);
Regex errorRegex = new Regex(@"^ERROR :(?<Message>.+)", RegexOptions.None);
Regex CTCPRegex = new Regex(@"^\u0001(?<Command>[^\s]+)\s?(?<Args>.*)\u0001", RegexOptions.None);
string[] messages = tcpMessage.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
@ -96,27 +98,58 @@ namespace Combot.IRCServices.Messaging @@ -96,27 +98,58 @@ namespace Combot.IRCServices.Messaging
{
// The message was a private message to a channel or nick
case "PRIVMSG":
if (recipient.StartsWith("&") || recipient.StartsWith("#"))
if (CTCPRegex.IsMatch(args))
{
ChannelMessage msg = new ChannelMessage();
msg.Channel = recipient;
msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
msg.Message = args;
Match ctcpMatch = CTCPRegex.Match(args);
CTCPMessage ctcpMessage = new CTCPMessage();
ctcpMessage.Target = new Nick()
{
Nickname = senderNick,
Realname = senderRealname,
Host = senderHost
};
ctcpMessage.Command = ctcpMatch.Groups["Command"].Value;
ctcpMessage.Arguments = ctcpMatch.Groups["Args"].Value;
if (ChannelMessageReceivedEvent != null)
if (CTCPMessageRecievedEvent != null)
{
ChannelMessageReceivedEvent(this, msg);
CTCPMessageRecievedEvent(this, ctcpMessage);
}
}
else
{
PrivateMessage msg = new PrivateMessage();
msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
msg.Message = args;
if (recipient.StartsWith("&") || recipient.StartsWith("#"))
{
ChannelMessage msg = new ChannelMessage();
msg.Channel = recipient;
msg.Sender = new Nick()
{
Nickname = senderNick,
Realname = senderRealname,
Host = senderHost
};
msg.Message = args;
if (PrivateMessageReceivedEvent != null)
if (ChannelMessageReceivedEvent != null)
{
ChannelMessageReceivedEvent(this, msg);
}
}
else
{
PrivateMessageReceivedEvent(this, msg);
PrivateMessage msg = new PrivateMessage();
msg.Sender = new Nick()
{
Nickname = senderNick,
Realname = senderRealname,
Host = senderHost
};
msg.Message = args;
if (PrivateMessageReceivedEvent != null)
{
PrivateMessageReceivedEvent(this, msg);
}
}
}
break;

15
IRCServices/Nick.cs

@ -31,6 +31,21 @@ namespace Combot.IRCServices @@ -31,6 +31,21 @@ namespace Combot.IRCServices
Privileges = new List<PrivilegeMode>();
}
public void Copy(Nick nick)
{
Username = nick.Username;
Realname = nick.Realname;
Host = nick.Host;
Nickname = nick.Nickname;
Password = nick.Password;
Identified = nick.Identified;
Registered = nick.Registered;
Modes = new List<UserMode>();
Modes.AddRange(nick.Modes);
Privileges = new List<PrivilegeMode>();
Privileges.AddRange(nick.Privileges);
}
public void AddMode(UserMode mode)
{
if (!Modes.Contains(mode))

17
Interface/ViewModels/MainViewModel.cs

@ -7,6 +7,8 @@ using System.Net; @@ -7,6 +7,8 @@ using System.Net;
using Combot;
using Combot.IRCServices.Messaging;
using Combot.Configurations;
using Combot.Modules;
using Combot.Modules.ModuleClasses;
namespace Interface.ViewModels
{
@ -35,16 +37,25 @@ namespace Interface.ViewModels @@ -35,16 +37,25 @@ namespace Interface.ViewModels
/*
ServerConfig serverConfig = new ServerConfig();
serverConfig.AutoConnect = true;
serverConfig.Channels = new List<ChannelConfig>() { new ChannelConfig() { Name = "#testing", Key = string.Empty } };
serverConfig.Channels = new List<ChannelConfig> { new ChannelConfig() { Name = "#testing", Key = string.Empty } };
serverConfig.Name = "Rizon";
serverConfig.Nickname = "Combot_V3";
serverConfig.Realname = "Combot_Realname";
serverConfig.Username = "Combot_Username";
serverConfig.Hosts = new List<HostConfig>() { new HostConfig() { Host = "irc.rizon.net", Port = 6667 } };
serverConfig.Hosts = new List<HostConfig> { new HostConfig() { Host = "irc.rizon.net", Port = 6667 } };
serverConfig.Modules = new List<Module>
{
new Module
{
Name = "Ping Me",
ClassName = "PingMe",
Enabled = true,
Commands = new List<Command> { new Command { Name = "Ping Me", Triggers = new List<string>() {"pingme"} } }
}
};
Config.Servers.Add(serverConfig);
Config.SaveServers();
*/
foreach (ServerConfig server in Config.Servers)
{
Bot Combot = new Bot(server);

Loading…
Cancel
Save