Merge VerbCommandRouter and ChatCommandRouter

This commit is contained in:
Nikolay Kochulin 2019-11-17 13:36:09 +00:00
parent 3c3b34fe13
commit b0632cf3b7
15 changed files with 83 additions and 153 deletions

View File

@ -14,44 +14,46 @@ namespace JetKarmaBot
{ {
public class ChatCommandRouter : ICommandRouter public class ChatCommandRouter : ICommandRouter
{ {
public Telegram.Bot.Types.User Me { get; private set; } public Telegram.Bot.Types.User Me { get; set; }
[Inject] private Logger log; [Inject] private Logger log;
[Inject] private TelegramBotClient Client { get; set; } [Inject] private TelegramBotClient Client { get; set; }
public string Prefix => "/"; public string Prefix => SuperRouter == null ? "/" : SuperRouter.Prefix + SuperCommand + " ";
public ICommandRouter SuperRouter { get; set; }
public string SuperCommand { get; set; }
public async Task Start() public Task<bool> Execute(CommandString cs, MessageEventArgs args)
{
Me = await Client.GetMeAsync();
}
public Task<bool> Execute(object sender, MessageEventArgs args)
{ {
log.Debug("Message received"); log.Debug("Message received");
var text = args.Message.Text; var text = args.Message.Text;
if (CommandString.TryParse(text, out var cmd)) CommandString ncs;
if (cs == null)
{ {
if (cmd.UserName != null && cmd.UserName != Me.Username) if (!CommandString.TryParse(text, out ncs))
return Task.FromResult(false);
if (ncs.UserName != null && ncs.UserName != Me.Username)
{ {
// directed not at us! // directed not at us!
log.Debug("Message not directed at us"); log.Debug("Message not directed at us");
return Task.FromResult(false); return Task.FromResult(false);
} }
}
else
ncs = new CommandString(cs.Parameters[0], cs.Parameters.Skip(1).ToArray());
try try
{
if (commands.ContainsKey(ncs.Command))
{ {
if (commands.ContainsKey(cmd.Command)) log.Debug($"Handling message via {commands[ncs.Command].GetType().Name}");
{ return commands[ncs.Command].Execute(ncs, args);
log.Debug($"Handling message via {commands[cmd.Command].GetType().Name}");
return commands[cmd.Command].Execute(this, cmd, args);
}
}
catch (Exception e)
{
log.Error($"Error while handling command {cmd.Command}!");
log.Error(e);
} }
} }
catch (Exception e)
{
log.Error($"Error while handling command {ncs.Command}!");
log.Error(e);
}
return Task.FromResult(false); return Task.FromResult(false);
} }
@ -59,6 +61,8 @@ namespace JetKarmaBot
public void Add(IChatCommand c) public void Add(IChatCommand c)
{ {
log.ConditionalTrace($"Adding command {c.GetType().Name}"); log.ConditionalTrace($"Adding command {c.GetType().Name}");
c.Router = this;
c.OnMount();
foreach (var name in c.Names) foreach (var name in c.Names)
{ {
log.ConditionalTrace($"Mounting {c.GetType().Name} to {name}"); log.ConditionalTrace($"Mounting {c.GetType().Name} to {name}");
@ -77,9 +81,9 @@ namespace JetKarmaBot
List<string> names = c.Names.ToList(); List<string> names = c.Names.ToList();
for (int i = 0; i < names.Count - 1; i++) for (int i = 0; i < names.Count - 1; i++)
{ {
build = build + "/" + names[i] + "\n"; build = build + Prefix + names[i] + "\n";
} }
build += "/" + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>"; build += Prefix + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>";
pieces.Add(build); pieces.Add(build);
} }
return string.Join("\n", pieces); return string.Join("\n", pieces);
@ -92,9 +96,9 @@ namespace JetKarmaBot
List<string> names = c.Names.ToList(); List<string> names = c.Names.ToList();
for (int i = 0; i < names.Count - 1; i++) for (int i = 0; i < names.Count - 1; i++)
{ {
build = build + "/" + names[i] + "\n"; build = build + Prefix + names[i] + "\n";
} }
build += "/" + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>\n"; build += Prefix + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>\n";
build += string.Join("\n", c.Arguments.Select(ca => (!ca.Required ? "[" : "") + ca.Name + (!ca.Required ? "]" : "") + ": <i>" + getLocalizedCMDArgDesc(ca, loc) + "</i>")); build += string.Join("\n", c.Arguments.Select(ca => (!ca.Required ? "[" : "") + ca.Name + (!ca.Required ? "]" : "") + ": <i>" + getLocalizedCMDArgDesc(ca, loc) + "</i>"));
return build; return build;
} }

View File

@ -18,7 +18,7 @@ namespace JetKarmaBot.Commands
[Inject] [Inject]
private Logger log; private Logger log;
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {
@ -78,7 +78,7 @@ namespace JetKarmaBot.Commands
return true; return true;
} }
if (CommandRouter.Me.Id == recipientId) if (Router.Me.Id == recipientId)
{ {
await Client.SendTextMessageAsync( await Client.SendTextMessageAsync(
args.Message.Chat.Id, args.Message.Chat.Id,
@ -161,7 +161,6 @@ namespace JetKarmaBot.Commands
[Inject] KarmaContextFactory Db { get; set; } [Inject] KarmaContextFactory Db { get; set; }
[Inject] TelegramBotClient Client { get; set; } [Inject] TelegramBotClient Client { get; set; }
[Inject] Localization Locale { get; set; } [Inject] Localization Locale { get; set; }
[Inject] ChatCommandRouter CommandRouter { get; set; }
public string Description => "Awards/revokes an award to a user."; public string Description => "Awards/revokes an award to a user.";
public string DescriptionID => "jetkarmabot.award.help"; public string DescriptionID => "jetkarmabot.award.help";
@ -182,5 +181,7 @@ namespace JetKarmaBot.Commands
DescriptionID="jetkarmabot.award.tohelp" DescriptionID="jetkarmabot.award.tohelp"
} }
}; };
public ICommandRouter Router { get; set; }
} }
} }

View File

@ -15,19 +15,22 @@ namespace JetKarmaBot.Commands
public string DescriptionID => "jetkarmabot.at.help"; public string DescriptionID => "jetkarmabot.at.help";
public VerbCommandRouter Router; public ChatCommandRouter VerbRouter;
[Inject] TelegramBotClient Client { get; set; } [Inject] TelegramBotClient Client { get; set; }
[Inject] Localization Locale { get; set; } [Inject] Localization Locale { get; set; }
[Inject] KarmaContextFactory Db { get; set; } [Inject] KarmaContextFactory Db { get; set; }
[Inject] IContainer C { get; set; }
public AwardTypeCommand(IContainer c, VerbCommandRouter r) public void OnMount()
{ {
Router = r; VerbRouter = C.ResolveObject(new ChatCommandRouter());
Router.SuperCommand = "at"; VerbRouter.SuperCommand = "at";
r.Add(c.GetInstance<AwardTypeManage.CreateCommand>()); VerbRouter.SuperRouter = Router;
r.Add(c.GetInstance<AwardTypeManage.RemoveCommand>()); VerbRouter.Me = Router.Me;
r.Add(c.GetInstance<AwardTypeManage.SetParameterCommand>()); VerbRouter.Add(C.GetInstance<AwardTypeManage.CreateCommand>());
r.Add(c.GetInstance<HelpCommand>()); VerbRouter.Add(C.GetInstance<AwardTypeManage.RemoveCommand>());
VerbRouter.Add(C.GetInstance<AwardTypeManage.SetParameterCommand>());
VerbRouter.Add(C.GetInstance<HelpCommand>());
} }
public IReadOnlyCollection<ChatCommandArgument> Arguments => new[] { public IReadOnlyCollection<ChatCommandArgument> Arguments => new[] {
@ -40,13 +43,15 @@ namespace JetKarmaBot.Commands
} }
}; };
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public ICommandRouter Router { get; set; }
public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
Router.SuperRouter = route; VerbRouter.SuperRouter = Router;
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {
var currentLocale = Locale[(await db.Chats.FindAsync(args.Message.Chat.Id)).Locale]; var currentLocale = Locale[(await db.Chats.FindAsync(args.Message.Chat.Id)).Locale];
if (!await Router.Process(route, cmd, args)) if (!await VerbRouter.Execute(cmd, args))
{ {
await Client.SendTextMessageAsync( await Client.SendTextMessageAsync(
args.Message.Chat.Id, args.Message.Chat.Id,

View File

@ -60,7 +60,9 @@ namespace JetKarmaBot.Commands.AwardTypeManage
} }
}; };
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public ICommandRouter Router { get; set; }
public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {

View File

@ -33,7 +33,9 @@ namespace JetKarmaBot.Commands.AwardTypeManage
} }
}; };
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public ICommandRouter Router { get; set; }
public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {

View File

@ -46,7 +46,10 @@ namespace JetKarmaBot.Commands.AwardTypeManage
DescriptionID="jetkarmabot.at.set.valuehelp" DescriptionID="jetkarmabot.at.set.valuehelp"
} }
}; };
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args)
public ICommandRouter Router { get; set; }
public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {

View File

@ -15,7 +15,7 @@ namespace JetKarmaBot.Commands
[Inject] [Inject]
private Logger log; private Logger log;
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {
@ -92,5 +92,7 @@ namespace JetKarmaBot.Commands
DescriptionID="jetkarmabot.changelocale.localehelp" DescriptionID="jetkarmabot.changelocale.localehelp"
} }
}; };
public ICommandRouter Router { get; set; }
} }
} }

View File

@ -23,7 +23,9 @@ namespace JetKarmaBot.Commands
public IReadOnlyCollection<ChatCommandArgument> Arguments => new ChatCommandArgument[] { public IReadOnlyCollection<ChatCommandArgument> Arguments => new ChatCommandArgument[] {
}; };
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public ICommandRouter Router { get; set; }
public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {

View File

@ -28,7 +28,9 @@ namespace JetKarmaBot.Commands
} }
}; };
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public ICommandRouter Router { get; set; }
public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {
@ -37,7 +39,7 @@ namespace JetKarmaBot.Commands
{ {
await Client.SendTextMessageAsync( await Client.SendTextMessageAsync(
args.Message.Chat.Id, args.Message.Chat.Id,
route.GetHelpText(currentLocale), Router.GetHelpText(currentLocale),
replyToMessageId: args.Message.MessageId, replyToMessageId: args.Message.MessageId,
parseMode: ParseMode.Html); parseMode: ParseMode.Html);
return true; return true;
@ -46,7 +48,7 @@ namespace JetKarmaBot.Commands
{ {
await Client.SendTextMessageAsync( await Client.SendTextMessageAsync(
args.Message.Chat.Id, args.Message.Chat.Id,
route.GetHelpTextFor(cmd.Parameters[0], currentLocale), Router.GetHelpTextFor(cmd.Parameters[0], currentLocale),
replyToMessageId: args.Message.MessageId, replyToMessageId: args.Message.MessageId,
parseMode: ParseMode.Html); parseMode: ParseMode.Html);
return true; return true;

View File

@ -10,8 +10,10 @@ namespace JetKarmaBot.Commands
string Description { get; } string Description { get; }
string DescriptionID { get; } string DescriptionID { get; }
IReadOnlyCollection<ChatCommandArgument> Arguments { get; } IReadOnlyCollection<ChatCommandArgument> Arguments { get; }
ICommandRouter Router { get; set; }
Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs messageEventArgs); Task<bool> Execute(CommandString cmd, MessageEventArgs messageEventArgs);
void OnMount() { }
} }
public struct ChatCommandArgument public struct ChatCommandArgument

View File

@ -17,7 +17,7 @@ namespace JetKarmaBot.Commands
{ {
public IReadOnlyCollection<string> Names => new[] { "leaderboard" }; public IReadOnlyCollection<string> Names => new[] { "leaderboard" };
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {
@ -77,5 +77,7 @@ namespace JetKarmaBot.Commands
DescriptionID= "jetkarmabot.leaderboard.awardtypehelp" DescriptionID= "jetkarmabot.leaderboard.awardtypehelp"
} }
}; };
public ICommandRouter Router { get; set; }
} }
} }

View File

@ -17,7 +17,7 @@ namespace JetKarmaBot.Commands
{ {
public IReadOnlyCollection<string> Names => new[] { "status" }; public IReadOnlyCollection<string> Names => new[] { "status" };
public async Task<bool> Execute(ICommandRouter route, CommandString cmd, MessageEventArgs args) public async Task<bool> Execute(CommandString cmd, MessageEventArgs args)
{ {
using (var db = Db.GetContext()) using (var db = Db.GetContext())
{ {
@ -100,5 +100,7 @@ namespace JetKarmaBot.Commands
DescriptionID= "jetkarmabot.status.awardtypehelp" DescriptionID= "jetkarmabot.status.awardtypehelp"
} }
}; };
public ICommandRouter Router { get; set; }
} }
} }

View File

@ -4,6 +4,7 @@ namespace JetKarmaBot
{ {
public interface ICommandRouter public interface ICommandRouter
{ {
Telegram.Bot.Types.User Me { get; set; }
string GetHelpText(Locale loc); string GetHelpText(Locale loc);
string GetHelpTextFor(string commandname, Locale loc); string GetHelpTextFor(string commandname, Locale loc);
void Add(IChatCommand c); void Add(IChatCommand c);

View File

@ -65,7 +65,7 @@ namespace JetKarmaBot
db.Chats.Add(new Models.Chat { ChatId = messageEventArgs.Message.Chat.Id }); db.Chats.Add(new Models.Chat { ChatId = messageEventArgs.Message.Chat.Id });
await db.SaveChangesAsync(); await db.SaveChangesAsync();
} }
await Commands.Execute(sender, messageEventArgs); await Commands.Execute(null, messageEventArgs);
}); });
} }
@ -84,8 +84,8 @@ namespace JetKarmaBot
async Task InitCommands(IContainer c) async Task InitCommands(IContainer c)
{ {
Commands = c.GetInstance<ChatCommandRouter>(); Commands = c.ResolveObject(new ChatCommandRouter());
await Commands.Start(); Commands.Me = await Client.GetMeAsync();
Commands.Add(c.GetInstance<HelpCommand>()); Commands.Add(c.GetInstance<HelpCommand>());
Commands.Add(c.GetInstance<AwardCommand>()); Commands.Add(c.GetInstance<AwardCommand>());
Commands.Add(c.GetInstance<StatusCommand>()); Commands.Add(c.GetInstance<StatusCommand>());

View File

@ -1,100 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JetKarmaBot.Commands;
using NLog;
using Perfusion;
using Telegram.Bot.Args;
namespace JetKarmaBot
{
public class VerbCommandRouter : ICommandRouter
{
Dictionary<string, IChatCommand> commands = new Dictionary<string, IChatCommand>();
[Inject] private Logger log;
public string SuperCommand { get; set; }
public string Prefix => SuperRouter.Prefix + SuperCommand + " ";
public ICommandRouter SuperRouter { get; set; }
public Task<bool> Process(ICommandRouter route, CommandString cs, MessageEventArgs args)
{
log.Debug($"(verb for {SuperCommand}) Processing verb");
if (cs.Parameters.Length < 1)
{
log.Debug($"(verb for {SuperCommand}) too few arguments");
return Task.FromResult(false);
}
CommandString ncs = new CommandString(cs.Parameters[0], cs.Parameters.Skip(1).ToArray());
try
{
if (commands.ContainsKey(ncs.Command))
{
log.Debug($"(verb for {SuperCommand}) Handling via {commands[ncs.Command].GetType().Name}");
return commands[ncs.Command].Execute(this, ncs, args);
}
}
catch (Exception e)
{
log.Error($"(verb for {SuperCommand}) Error while handling verb {ncs.Command}!");
log.Error(e);
return Task.FromResult(true); //Don't trigger message
}
return Task.FromResult(false);
}
public void Add(IChatCommand c)
{
log.ConditionalTrace($"(verb for {SuperCommand}) Adding command {c.GetType().Name}");
foreach (var name in c.Names)
{
log.ConditionalTrace($"(verb for {SuperCommand}) Mounting {c.GetType().Name} to {name}");
if (commands.ContainsKey(name))
throw new Exception($"command collision for name {name}, commands {commands[name].GetType()} and {c.GetType()}");
commands[name] = c;
}
}
public string GetHelpText(Locale loc)
{
List<string> pieces = new List<string>();
foreach (IChatCommand c in commands.Values.Distinct())
{
string build = "";
List<string> names = c.Names.ToList();
for (int i = 0; i < names.Count - 1; i++)
{
build = build + Prefix + names[i] + "\n";
}
build += "<a href=\"http://example.com\">" + Prefix + names[names.Count - 1] + "</a> " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>";
pieces.Add(build);
}
return string.Join("\n", pieces);
}
public string GetHelpTextFor(string commandname, Locale loc)
{
IChatCommand c = commands[commandname];
string build = "";
List<string> names = c.Names.ToList();
for (int i = 0; i < names.Count - 1; i++)
{
build = build + Prefix + names[i] + "\n";
}
build += Prefix + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>\n";
build += string.Join("\n", c.Arguments.Select(ca => (!ca.Required ? "[" : "") + ca.Name + (!ca.Required ? "]" : "") + ": <i>" + getLocalizedCMDArgDesc(ca, loc) + "</i>"));
return build;
}
private string getLocalizedCMDDesc(IChatCommand cmd, Locale loc)
{
if (loc.ContainsKey(cmd.DescriptionID)) return loc[cmd.DescriptionID];
else return cmd.Description;
}
private string getLocalizedCMDArgDesc(ChatCommandArgument arg, Locale loc)
{
if (loc.ContainsKey(arg.DescriptionID)) return loc[arg.DescriptionID];
else return arg.Description;
}
}
}