diff --git a/.gitignore b/.gitignore
index 39c9242..d0e2a2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ obj/
riderModule.iml
/_ReSharper.Caches/
.idea/
+/.vs/TgBotFramework
diff --git a/examples/EchoBotProject/EchoBotProject.csproj b/examples/EchoBotProject/EchoBotProject.csproj
index 0995763..8352342 100644
--- a/examples/EchoBotProject/EchoBotProject.csproj
+++ b/examples/EchoBotProject/EchoBotProject.csproj
@@ -4,6 +4,16 @@
net5.0
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/EchoBotProject/Handlers/PublicChatEcho.cs b/examples/EchoBotProject/Handlers/PublicChatEcho.cs
index aa283ca..0a290b0 100644
--- a/examples/EchoBotProject/Handlers/PublicChatEcho.cs
+++ b/examples/EchoBotProject/Handlers/PublicChatEcho.cs
@@ -3,21 +3,27 @@
using Microsoft.Extensions.Logging;
using Telegram.Bot;
using TgBotFramework;
+using TgBotFramework.Attributes;
+using TgBotFramework.MessageReader;
using TgBotFramework.WrapperExtensions;
namespace EchoBotProject.Handlers
{
+ [Handler("publicChat")]
public class PublicChatEcho : IUpdateHandler
{
private readonly ILogger _logger;
+ private readonly IMessageReader _messageReader;
- public PublicChatEcho(ILogger logger)
+ public PublicChatEcho(ILogger logger, IMessageReader messageReader)
{
+ _messageReader = messageReader;
_logger = logger;
}
public async Task HandleAsync(BotExampleContext context, UpdateDelegate next, CancellationToken cancellationToken)
{
+ await context.Client.SendTextMessageAsync(context.Update.GetSenderId(), _messageReader.GetMessage("greetings"));
_logger.LogInformation("This update {0} was from public chat {1}", context.Update.Id, context.Update.GetChat());
}
}
diff --git a/examples/EchoBotProject/Resources/ru/game.stage.json b/examples/EchoBotProject/Resources/ru/game.stage.json
new file mode 100644
index 0000000..d414d58
--- /dev/null
+++ b/examples/EchoBotProject/Resources/ru/game.stage.json
@@ -0,0 +1,5 @@
+{
+ "exit": "Okay, you got out, lets play ping-pong with counter",
+ "exit.provocativeMessage": "Cmon, find EXIT"
+
+}
\ No newline at end of file
diff --git a/examples/EchoBotProject/Resources/ru/publicChat.handler.json b/examples/EchoBotProject/Resources/ru/publicChat.handler.json
new file mode 100644
index 0000000..763a574
--- /dev/null
+++ b/examples/EchoBotProject/Resources/ru/publicChat.handler.json
@@ -0,0 +1,3 @@
+{
+ "greetings": "Hello, my dear friend!"
+}
\ No newline at end of file
diff --git a/examples/EchoBotProject/States/GameState.cs b/examples/EchoBotProject/States/GameState.cs
index 289a778..6489e60 100644
--- a/examples/EchoBotProject/States/GameState.cs
+++ b/examples/EchoBotProject/States/GameState.cs
@@ -5,22 +5,30 @@
using TgBotFramework;
using TgBotFramework.Attributes;
using TgBotFramework.WrapperExtensions;
+using TgBotFramework.MessageReader;
namespace EchoBotProject.States
{
[State(Stage = "game")]
public class GameState : BasicState where TContext : IUpdateContext
{
+ private readonly IMessageReader, TContext> _messageReader;
+
+ public GameState(IMessageReader, TContext> messageReader)
+ {
+ _messageReader = messageReader;
+ }
+
public override async Task HandleAsync(TContext context, UpdateDelegate next, CancellationToken cancellationToken)
{
if (context.Update.Message?.Text != null && context.Update.Message.Text == "/exit")
{
- await context.Client.SendTextMessageAsync(context.Update.GetChat(), "Okay, you got out, lets play ping-pong with counter", cancellationToken: cancellationToken);
+ await context.Client.SendTextMessageAsync(context.Update.GetChat(), _messageReader.GetMessage("exit"), cancellationToken: cancellationToken);
await Exit(context);
}
else
{
- await context.Client.SendTextMessageAsync(context.Update.GetChat(), "Cmon, find EXIT", cancellationToken: cancellationToken);
+ await context.Client.SendTextMessageAsync(context.Update.GetChat(), _messageReader.GetMessage("exit.provocativeMessage"), cancellationToken: cancellationToken);
}
}
}
diff --git a/examples/EchoBotWebExample/EchoBotWebExample.csproj.user b/examples/EchoBotWebExample/EchoBotWebExample.csproj.user
new file mode 100644
index 0000000..cff74a9
--- /dev/null
+++ b/examples/EchoBotWebExample/EchoBotWebExample.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ IIS Express
+
+
\ No newline at end of file
diff --git a/examples/EchoBotWebExample/Properties/launchSettings.json b/examples/EchoBotWebExample/Properties/launchSettings.json
new file mode 100644
index 0000000..5cfef87
--- /dev/null
+++ b/examples/EchoBotWebExample/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:56028/",
+ "sslPort": 44336
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "EchoBotWebExample": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "https://localhost:5001;http://localhost:5000"
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/EchoBotWebExample/Startup.cs b/examples/EchoBotWebExample/Startup.cs
index b1cecc9..c466bf8 100644
--- a/examples/EchoBotWebExample/Startup.cs
+++ b/examples/EchoBotWebExample/Startup.cs
@@ -15,9 +15,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
-using Telegram.Bot;
using TgBotFramework;
-using TgBotFramework.UpdatePipeline;
namespace EchoBotWebExample
{
@@ -42,11 +40,9 @@ public void ConfigureServices(IServiceCollection services)
services.AddScoped();
services.AddScoped();
-
// register deps for pipeline
services.ServicesForExamplePipelineBuilder();
-
-
+
services.AddDbContext(x =>
x.UseSqlite("Data Source=BotFramework.db",
builder => builder.MigrationsAssembly("EchoBotProject")));
@@ -59,7 +55,9 @@ public void ConfigureServices(IServiceCollection services)
.UseMiddleware()
-
+ .AddMessageReader()
+ .AddMessageReader>()
+
// you may use this approach to logging but be aware that not all update objects can be converted back to json
.UseMiddleware()
// if you want to use states...
diff --git a/examples/WebhookExample/Properties/launchSettings.json b/examples/WebhookExample/Properties/launchSettings.json
new file mode 100644
index 0000000..a473bdf
--- /dev/null
+++ b/examples/WebhookExample/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:56027/",
+ "sslPort": 44374
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "WebhookExample": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "https://localhost:5001;http://localhost:5000"
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/WebhookExample/WebhookExample.csproj.user b/examples/WebhookExample/WebhookExample.csproj.user
new file mode 100644
index 0000000..cff74a9
--- /dev/null
+++ b/examples/WebhookExample/WebhookExample.csproj.user
@@ -0,0 +1,6 @@
+
+
+
+ IIS Express
+
+
\ No newline at end of file
diff --git a/src/TgBotFramework/Attributes/HandlerAttribute.cs b/src/TgBotFramework/Attributes/HandlerAttribute.cs
new file mode 100644
index 0000000..77a0e92
--- /dev/null
+++ b/src/TgBotFramework/Attributes/HandlerAttribute.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TgBotFramework.Attributes
+{
+ public class HandlerAttribute : System.Attribute
+ {
+ public string Stage { get; }
+
+ public HandlerAttribute(string stage)
+ {
+ Stage = stage;
+ }
+ }
+}
diff --git a/src/TgBotFramework/BotFrameworkBuilder.cs b/src/TgBotFramework/BotFrameworkBuilder.cs
index e0edbbc..fe7803c 100644
--- a/src/TgBotFramework/BotFrameworkBuilder.cs
+++ b/src/TgBotFramework/BotFrameworkBuilder.cs
@@ -7,6 +7,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using TgBotFramework.Attributes;
+using TgBotFramework.MessageReader;
using TgBotFramework.StageManaging;
using TgBotFramework.UpdatePipeline;
@@ -42,6 +43,13 @@ public BotFrameworkBuilder(IServiceCollection services)
services.AddSingleton(provider => provider.GetService());
}
+ public IBotFrameworkBuilder AddMessageReader(string rootDirectory = "Resources", string language = "ru", Assembly resourceAssembly = null)
+ where TUpdateHandler : class
+ {
+ Services.AddSingleton>(provider => new MessageReader(rootDirectory, language, resourceAssembly));
+ return this;
+ }
+
public IBotFrameworkBuilder UseLongPolling(LongPollingOptions longPollingOptions) where T : BackgroundService, IPollingManager
{
Services.AddHostedService();
diff --git a/src/TgBotFramework/IBotFrameworkBuilder.cs b/src/TgBotFramework/IBotFrameworkBuilder.cs
index 7608f1d..0e4731c 100644
--- a/src/TgBotFramework/IBotFrameworkBuilder.cs
+++ b/src/TgBotFramework/IBotFrameworkBuilder.cs
@@ -25,5 +25,8 @@ IBotFrameworkBuilder SetPipeline(
IBotFrameworkBuilder UseStates(Assembly assembly);
IBotFrameworkBuilder UseCommands(Assembly getAssembly);
+
+ IBotFrameworkBuilder AddMessageReader(string rootDirectory = "Resources", string language = "ru", Assembly resourceAssembly = null)
+ where TUpdateHandler : class;
}
}
\ No newline at end of file
diff --git a/src/TgBotFramework/MessageReader/IMessageReader.cs b/src/TgBotFramework/MessageReader/IMessageReader.cs
new file mode 100644
index 0000000..6c11ea1
--- /dev/null
+++ b/src/TgBotFramework/MessageReader/IMessageReader.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TgBotFramework.MessageReader
+{
+ public interface IMessageReader
+ where TContext : IUpdateContext
+ where TUpdateHandler : class
+ {
+ string GetMessage(string jsonPath);
+ }
+}
diff --git a/src/TgBotFramework/MessageReader/MessageReader.cs b/src/TgBotFramework/MessageReader/MessageReader.cs
new file mode 100644
index 0000000..7e79359
--- /dev/null
+++ b/src/TgBotFramework/MessageReader/MessageReader.cs
@@ -0,0 +1,78 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.IO;
+using System.Reflection;
+using TgBotFramework.Attributes;
+
+namespace TgBotFramework.MessageReader
+{
+ public class MessageReader : IMessageReader
+ where TContext : IUpdateContext
+ where TUpdateHandler : class
+ {
+ private readonly Assembly _resourceAssembly;
+ private readonly string _rootDirectory;
+ private readonly string _language;
+ private readonly string _stage;
+ private readonly Stream _stream;
+ private readonly StreamReader _fileReader;
+
+ public MessageReader(string rootDirectory = "Resources", string language = "ru", Assembly resourceAssembly = null)
+ {
+ _rootDirectory = rootDirectory;
+ _language = language;
+ _resourceAssembly = resourceAssembly ?? Assembly.GetCallingAssembly();
+
+ var handlerAttribute = typeof(TUpdateHandler).GetCustomAttribute();
+ if (handlerAttribute != null)
+ {
+ _stage = handlerAttribute.Stage + ".handler";
+ }
+ else
+ {
+ var stateAttribute = typeof(TUpdateHandler).GetCustomAttribute();
+ if (stateAttribute != null)
+ {
+ _stage = stateAttribute.Stage + ".stage";
+ }
+ }
+
+ if (_stage == null)
+ {
+ throw new InvalidOperationException("The IUpdateHandler class should contain State or Handler attribute");
+ }
+
+ var resourcePath = $"{_resourceAssembly.GetName().Name}.{_rootDirectory}.{_language}.{_stage}.json";
+ _stream = _resourceAssembly.GetManifestResourceStream(resourcePath);
+
+ if (_stream == null)
+ {
+ throw new InvalidOperationException(
+ $"Assembly {_resourceAssembly.FullName} doesn't contain EmbeddedResource at path {resourcePath}. Resource file cannot be loaded");
+ }
+
+ _fileReader = new StreamReader(_stream);
+ MessageFileText = _fileReader.ReadToEnd();
+ }
+
+ public string MessageFileText { get; private set; }
+
+ public void Dispose()
+ {
+ _fileReader.Close();
+ _stream.Close();
+ }
+
+ public string GetMessage(string jsonPath)
+ {
+ JObject JsonObject = JsonConvert.DeserializeObject(MessageFileText);
+ var node = JsonObject.SelectToken(jsonPath);
+ if (node == null)
+ {
+ throw new ArgumentException($"There are no values found by path '{jsonPath}' in stage JSON file '{_stage}'");
+ }
+ return node.ToString();
+ }
+ }
+}