Browse Source

Added Module loading and running.

Added command parsing to bot.
Added initial PingMe module as POC.
tags/3.0.0
Teknikode 4 years ago
parent
commit
f2b81f19b8

+ 58
- 0
Combot/Bot.cs View File

@@ -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
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
}
}
}

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);
}
}
}
}
}
}

+ 6
- 1
Combot/Combot.csproj View File

@@ -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 @@
<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.

+ 0
- 22
Combot/Command.cs View File

@@ -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; }
}
}

+ 47
- 5
Combot/Configurations/ServerConfig.cs View File

@@ -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
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
}
}

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
}
}

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
- 0
Combot/Modules/Command.cs View File

@@ -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
- 0
Combot/Modules/CommandArgument.cs View File

@@ -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
- 0
Combot/Modules/CommandMessage.cs View File

@@ -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>();
}
}
}

+ 78
- 3
Combot/Modules/Module.cs View File

@@ -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
- 0
Combot/Modules/ModuleClasses/PingMe.cs View File

@@ -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
- 0
Combot/Modules/Option.cs View File

@@ -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;
}
}
}

+ 2
- 2
IRCServices/IRC.cs View File

@@ -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()
{

+ 7
- 3
IRCServices/Messaging/MessageTypes.cs View File

@@ -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
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; }

+ 45
- 12
IRCServices/Messaging/Messages.cs View File

@@ -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
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
{
// 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
- 0
IRCServices/Nick.cs View File

@@ -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))

+ 14
- 3
Interface/ViewModels/MainViewModel.cs View File

@@ -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
/*
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