mirror of
https://github.com/Jetsparrow/jetherald.git
synced 2026-01-20 23:56:08 +03:00
Initial release
This commit is contained in:
commit
a8485edcf9
45
.gitignore
vendored
Normal file
45
.gitignore
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
# Autosave files
|
||||
*~
|
||||
|
||||
# build
|
||||
[Oo]bj/
|
||||
[Bb]in/
|
||||
packages/
|
||||
TestResults/
|
||||
|
||||
# globs
|
||||
Makefile.in
|
||||
*.DS_Store
|
||||
*.sln.cache
|
||||
*.suo
|
||||
*.cache
|
||||
*.pidb
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.log
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.user
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
Thumbs.db
|
||||
.vs/
|
||||
|
||||
# Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
# resharper
|
||||
*_Resharper.*
|
||||
*.Resharper
|
||||
|
||||
# dotCover
|
||||
*.dotCover
|
||||
|
||||
#secret config
|
||||
karma.cfg.json
|
||||
*secrets.ini
|
||||
25
JetHerald.sln
Normal file
25
JetHerald.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28307.539
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JetHerald", "JetHerald\JetHerald.csproj", "{B48207B2-F0A8-4BD8-AF92-906D128EF152}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B48207B2-F0A8-4BD8-AF92-906D128EF152}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B48207B2-F0A8-4BD8-AF92-906D128EF152}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B48207B2-F0A8-4BD8-AF92-906D128EF152}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B48207B2-F0A8-4BD8-AF92-906D128EF152}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {A8B3E56D-CF82-4D94-B2CD-396A1AF6718B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
65
JetHerald/ChatCommandRouter.cs
Normal file
65
JetHerald/ChatCommandRouter.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegram.Bot.Args;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public interface IChatCommand
|
||||
{
|
||||
Task<string> Execute(CommandString cmd, MessageEventArgs messageEventArgs);
|
||||
}
|
||||
|
||||
public class ChatCommandRouter
|
||||
{
|
||||
string Username { get; }
|
||||
ILogger Log { get; }
|
||||
|
||||
public ChatCommandRouter(string username, ILogger log)
|
||||
{
|
||||
Log = log;
|
||||
Username = username;
|
||||
}
|
||||
|
||||
public async Task<string> Execute(object sender, MessageEventArgs args)
|
||||
{
|
||||
var text = args.Message.Text;
|
||||
if (CommandString.TryParse(text, out var cmd))
|
||||
{
|
||||
if (cmd.UserName != null && cmd.UserName != Username)
|
||||
{
|
||||
Log.LogDebug("Message not directed at us");
|
||||
return null;
|
||||
}
|
||||
if (commands.ContainsKey(cmd.Command))
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.LogDebug($"Handling message via {commands[cmd.Command].GetType().Name}");
|
||||
return await commands[cmd.Command].Execute(cmd, args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.LogError(e, $"Error while executing command {cmd.Command}!");
|
||||
}
|
||||
}
|
||||
else
|
||||
Log.LogDebug($"Command {cmd.Command} not found");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Add(IChatCommand c, params string[] cmds)
|
||||
{
|
||||
foreach (var cmd in cmds)
|
||||
{
|
||||
if (commands.ContainsKey(cmd))
|
||||
throw new ArgumentException($"collision for {cmd}, commands {commands[cmd].GetType()} and {c.GetType()}");
|
||||
commands[cmd] = c;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, IChatCommand> commands = new Dictionary<string, IChatCommand>();
|
||||
}
|
||||
}
|
||||
42
JetHerald/CommandString.cs
Normal file
42
JetHerald/CommandString.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public class CommandString
|
||||
{
|
||||
public CommandString(string command, string username, params string[] parameters)
|
||||
{
|
||||
Command = command;
|
||||
Parameters = parameters;
|
||||
}
|
||||
|
||||
public string Command { get; }
|
||||
public string UserName { get; }
|
||||
public string[] Parameters { get; }
|
||||
|
||||
static readonly char[] WS_CHARS = new[] { ' ', '\r', '\n', '\n' };
|
||||
|
||||
public static bool TryParse(string s, out CommandString result)
|
||||
{
|
||||
result = null;
|
||||
if (string.IsNullOrWhiteSpace(s) || s[0] != '/')
|
||||
return false;
|
||||
|
||||
string[] words = s.Split(WS_CHARS, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var cmdRegex = new Regex(@"/(?<cmd>\w+)(@(?<name>\w+))?");
|
||||
var match = cmdRegex.Match(words.First());
|
||||
if (!match.Success)
|
||||
return false;
|
||||
|
||||
string cmd = match.Groups["cmd"].Captures[0].Value;
|
||||
string username = match.Groups["name"].Captures.Count > 0 ? match.Groups["name"].Captures[0].Value : null;
|
||||
string[] parameters = words.Skip(1).ToArray();
|
||||
|
||||
result = new CommandString(cmd, username, parameters);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
JetHerald/Commands/CreateTopicCommand.cs
Normal file
47
JetHerald/Commands/CreateTopicCommand.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Telegram.Bot.Args;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
|
||||
namespace JetHerald.Commands
|
||||
{
|
||||
public class CreateTopicCommand : IChatCommand
|
||||
{
|
||||
Db db;
|
||||
|
||||
public CreateTopicCommand(Db db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<string> Execute(CommandString cmd, MessageEventArgs messageEventArgs)
|
||||
{
|
||||
if (cmd.Parameters.Length < 1)
|
||||
return null;
|
||||
var msg = messageEventArgs.Message;
|
||||
var chatid = msg.Chat.Id;
|
||||
|
||||
if (msg.Chat.Type != ChatType.Private)
|
||||
return null;
|
||||
|
||||
string name = cmd.Parameters[0];
|
||||
string descr = name;
|
||||
if (cmd.Parameters.Length > 1)
|
||||
descr = string.Join(' ', cmd.Parameters.Skip(1));
|
||||
|
||||
try
|
||||
{
|
||||
var topic = await db.CreateTopic(msg.From.Id, name, descr);
|
||||
return $"created {topic.Name}\n" +
|
||||
$"readToken\n{topic.ReadToken}\n" +
|
||||
$"writeToken\n{topic.WriteToken}\n" +
|
||||
$"adminToken\n{topic.AdminToken}\n";
|
||||
}
|
||||
catch (MySqlException myDuplicate) when (myDuplicate.Number == 1062)
|
||||
{
|
||||
return $"topic {name} already exists";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
JetHerald/Commands/DeleteTopicCommand.cs
Normal file
33
JetHerald/Commands/DeleteTopicCommand.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Args;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
|
||||
namespace JetHerald.Commands
|
||||
{
|
||||
public class DeleteTopicCommand : IChatCommand
|
||||
{
|
||||
Db db;
|
||||
|
||||
public DeleteTopicCommand(Db db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<string> Execute(CommandString cmd, MessageEventArgs messageEventArgs)
|
||||
{
|
||||
if (cmd.Parameters.Length < 2)
|
||||
return null;
|
||||
var msg = messageEventArgs.Message;
|
||||
var chatid = msg.Chat.Id;
|
||||
|
||||
if (msg.Chat.Type != ChatType.Private)
|
||||
return null;
|
||||
|
||||
string name = cmd.Parameters[0];
|
||||
string adminToken = cmd.Parameters[1];
|
||||
|
||||
var topic = await db.DeleteTopic(name, adminToken);
|
||||
return $"deleted {name} and all its subscriptions";
|
||||
}
|
||||
}
|
||||
}
|
||||
31
JetHerald/Commands/ListCommand.cs
Normal file
31
JetHerald/Commands/ListCommand.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Args;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public class ListCommand : IChatCommand
|
||||
{
|
||||
Db db;
|
||||
|
||||
public ListCommand(Db db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<string> Execute(CommandString cmd, MessageEventArgs messageEventArgs)
|
||||
{
|
||||
var msg = messageEventArgs.Message;
|
||||
var chatid = msg.Chat.Id;
|
||||
var topics = await db.GetTopicsForChat(chatid);
|
||||
|
||||
return topics.Any()
|
||||
? "Topics:\n" + string.Join("\n", topics.Select(GetTopicListing))
|
||||
: "No subscriptions active.";
|
||||
}
|
||||
|
||||
static string GetTopicListing(Db.Topic t)
|
||||
=> t.Name == t.Description ? t.Name : $"{t.Name}: {t.Description}";
|
||||
|
||||
}
|
||||
}
|
||||
38
JetHerald/Commands/SubscribeCommand.cs
Normal file
38
JetHerald/Commands/SubscribeCommand.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Args;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public class SubscribeCommand : IChatCommand
|
||||
{
|
||||
Db db;
|
||||
|
||||
public SubscribeCommand(Db db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<string> Execute(CommandString cmd, MessageEventArgs args)
|
||||
{
|
||||
if (cmd.Parameters.Length < 1)
|
||||
return null;
|
||||
|
||||
var chatid = args.Message.Chat.Id;
|
||||
var token = cmd.Parameters[0];
|
||||
|
||||
var topic = await db.GetTopic(token, chatid);
|
||||
|
||||
if (topic == null)
|
||||
return "topic not found";
|
||||
else if (topic.ChatId == chatid)
|
||||
return $"already subscribed to {topic.Name}";
|
||||
else if (topic.ReadToken != token)
|
||||
return "token mismatch";
|
||||
else
|
||||
{
|
||||
await db.CreateSubscription(topic.TopicId, chatid);
|
||||
return $"subscribed to {topic.Name}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
JetHerald/Commands/UnsubscribeCommand.cs
Normal file
30
JetHerald/Commands/UnsubscribeCommand.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot.Args;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public class UnsubscribeCommand : IChatCommand
|
||||
{
|
||||
Db db;
|
||||
|
||||
public UnsubscribeCommand(Db db)
|
||||
{
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<string> Execute(CommandString cmd, MessageEventArgs messageEventArgs)
|
||||
{
|
||||
if (cmd.Parameters.Length < 1)
|
||||
return null;
|
||||
|
||||
var msg = messageEventArgs.Message;
|
||||
var chatid = msg.Chat.Id;
|
||||
var topicName = cmd.Parameters[0];
|
||||
int affected = await db.RemoveSubscription(topicName, chatid);
|
||||
if (affected >= 1)
|
||||
return $"unsubscribed from {topicName}";
|
||||
else
|
||||
return $"could not find subscription for {topicName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
17
JetHerald/Configs.cs
Normal file
17
JetHerald/Configs.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace JetHerald.Options
|
||||
{
|
||||
public class ConnectionStrings
|
||||
{
|
||||
public string DefaultConnection { get; set; }
|
||||
}
|
||||
|
||||
public class Telegram
|
||||
{
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
public bool UseProxy { get; set; }
|
||||
public string ProxyUrl { get; set; }
|
||||
public string ProxyPassword { get; set; }
|
||||
public string ProxyLogin { get; set; }
|
||||
}
|
||||
}
|
||||
42
JetHerald/Controllers/ReportController.cs
Normal file
42
JetHerald/Controllers/ReportController.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace JetHerald.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class ReportController : ControllerBase
|
||||
{
|
||||
Db Db { get; }
|
||||
JetHeraldBot Herald { get; }
|
||||
|
||||
public ReportController(Db db, JetHeraldBot herald)
|
||||
{
|
||||
Herald = herald;
|
||||
Db = db;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Post([FromBody] ReportArgs args)
|
||||
{
|
||||
var t = await Db.GetTopic(args.Topic);
|
||||
if (t == null)
|
||||
return new NotFoundResult();
|
||||
else if (!t.WriteToken.Equals(args.WriteToken, StringComparison.OrdinalIgnoreCase))
|
||||
return StatusCode(403);
|
||||
|
||||
await Herald.PublishMessage(t, args.Message);
|
||||
return new OkResult();
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class ReportArgs
|
||||
{
|
||||
[DataMember] public string Topic { get; set; }
|
||||
[DataMember] public string Message { get; set; }
|
||||
[DataMember] public string WriteToken { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
120
JetHerald/Db.cs
Normal file
120
JetHerald/Db.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Transactions;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public static class TokenHelper
|
||||
{
|
||||
static RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
|
||||
static byte[] buf = new byte[24];
|
||||
|
||||
public static string GetToken()
|
||||
{
|
||||
rng.GetBytes(buf);
|
||||
return Convert.ToBase64String(buf).Replace('+', '_').Replace('/','_');
|
||||
}
|
||||
}
|
||||
|
||||
public class Db
|
||||
{
|
||||
public class Topic
|
||||
{
|
||||
public uint TopicId { get; set; }
|
||||
public long CreatorId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string ReadToken { get; set; }
|
||||
public string WriteToken { get; set; }
|
||||
public string AdminToken { get; set; }
|
||||
|
||||
public long? ChatId { get; set; }
|
||||
}
|
||||
|
||||
public async Task<int> DeleteTopic(string name, string adminToken)
|
||||
{
|
||||
using (var c = GetConnection())
|
||||
{
|
||||
return await c.ExecuteAsync("DELETE FROM topic WHERE Name = @name AND AdminToken = @adminToken", new { name, adminToken });
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Topic> GetTopic(string name)
|
||||
{
|
||||
using (var c = GetConnection())
|
||||
return await c.QuerySingleOrDefaultAsync<Topic>("SELECT * FROM topic WHERE Name = @name", new { name });
|
||||
}
|
||||
|
||||
public async Task<Topic> GetTopic(string token, long chatId)
|
||||
{
|
||||
using (var c = GetConnection())
|
||||
return await c.QuerySingleOrDefaultAsync<Topic>(
|
||||
"SELECT t.*, tc.ChatId " +
|
||||
"FROM topic t LEFT JOIN topic_chat tc ON t.TopicId = tc.TopicId AND tc.ChatId = @chatId " +
|
||||
"WHERE ReadToken = @token", new { token, chatId});
|
||||
}
|
||||
|
||||
public async Task<Topic> CreateTopic(long userId, string name, string descr)
|
||||
{
|
||||
var t = new Topic
|
||||
{
|
||||
CreatorId = userId,
|
||||
Name = name,
|
||||
Description = descr,
|
||||
ReadToken = TokenHelper.GetToken(),
|
||||
WriteToken = TokenHelper.GetToken(),
|
||||
AdminToken = TokenHelper.GetToken()
|
||||
};
|
||||
using (var c = GetConnection())
|
||||
{
|
||||
return await c.QuerySingleOrDefaultAsync<Topic>(
|
||||
" INSERT INTO herald.topic " +
|
||||
" (TopicId, CreatorId, Name, Description, ReadToken, WriteToken, AdminToken) " +
|
||||
" VALUES " +
|
||||
" (NULL, @CreatorId, @Name, @Description, @ReadToken, @WriteToken, @AdminToken); " +
|
||||
" SELECT * FROM topic WHERE TopicId = LAST_INSERT_ID(); ",
|
||||
t);
|
||||
}
|
||||
}
|
||||
public async Task<IEnumerable<long>> GetChatIdsForTopic(uint topicid)
|
||||
{
|
||||
using (var c = GetConnection())
|
||||
return await c.QueryAsync<long>("SELECT ChatId FROM topic_chat WHERE TopicId = @topicid", new { topicid });
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Topic>> GetTopicsForChat(long chatid)
|
||||
{
|
||||
using (var c = GetConnection())
|
||||
return await c.QueryAsync<Topic>("SELECT t.* FROM topic_chat ct JOIN topic t on t.TopicId = ct.TopicId WHERE ct.ChatId = @chatid", new { chatid });
|
||||
}
|
||||
|
||||
public async Task CreateSubscription(uint topicId, long chatId)
|
||||
{
|
||||
using (var c = GetConnection())
|
||||
await c.ExecuteAsync("INSERT INTO topic_chat (ChatId, TopicId ) VALUES (@chatId, @topicId)", new { topicId, chatId });
|
||||
}
|
||||
|
||||
public async Task<int> RemoveSubscription(string topicName, long chatId)
|
||||
{
|
||||
using (var c = GetConnection())
|
||||
return await c.ExecuteAsync(
|
||||
"DELETE tc " +
|
||||
"FROM topic_chat tc JOIN topic t ON tc.TopicId = t.TopicId " +
|
||||
"WHERE t.Name = @topicName AND tc.ChatId = @chatId;",
|
||||
new { topicName, chatId });
|
||||
}
|
||||
|
||||
public Db(IOptions<Options.ConnectionStrings> cfg)
|
||||
{
|
||||
Config = cfg;
|
||||
}
|
||||
|
||||
IOptions<Options.ConnectionStrings> Config { get; }
|
||||
MySqlConnection GetConnection() => new MySqlConnection(Config.Value.DefaultConnection);
|
||||
}
|
||||
}
|
||||
27
JetHerald/JetHerald.csproj
Normal file
27
JetHerald/JetHerald.csproj
Normal file
@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="1.60.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.1" />
|
||||
<PackageReference Include="MySql.Data" Version="8.0.17" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.8.4" />
|
||||
<PackageReference Include="Telegram.Bot" Version="14.12.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
85
JetHerald/JetHeraldBot.cs
Normal file
85
JetHerald/JetHeraldBot.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Args;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
|
||||
using JetHerald.Commands;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public class JetHeraldBot
|
||||
{
|
||||
Db Db { get; set; }
|
||||
Options.Telegram Config { get; }
|
||||
ILogger<JetHeraldBot> Log { get; }
|
||||
|
||||
public JetHeraldBot(Db db, IOptions<Options.Telegram> cfg, ILogger<JetHeraldBot> log)
|
||||
{
|
||||
Db = db;
|
||||
Config = cfg.Value;
|
||||
Log = log;
|
||||
}
|
||||
|
||||
TelegramBotClient Client { get; set; }
|
||||
ChatCommandRouter Commands;
|
||||
Telegram.Bot.Types.User Me { get; set; }
|
||||
|
||||
public async Task Init()
|
||||
{
|
||||
if (Config.UseProxy)
|
||||
{
|
||||
Client = new TelegramBotClient(Config.ApiKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
var httpProxy = new WebProxy(Config.ProxyUrl)
|
||||
{ Credentials = new NetworkCredential(Config.ProxyLogin, Config.ProxyPassword) };
|
||||
Client = new TelegramBotClient(Config.ApiKey, httpProxy);
|
||||
}
|
||||
Me = await Client.GetMeAsync();
|
||||
|
||||
Commands = new ChatCommandRouter(Me.Username, Log);
|
||||
Commands.Add(new CreateTopicCommand(Db), "createtopic");
|
||||
Commands.Add(new DeleteTopicCommand(Db), "deletetopic");
|
||||
Commands.Add(new SubscribeCommand(Db), "subscribe", "sub");
|
||||
Commands.Add(new UnsubscribeCommand(Db), "unsubscribe", "unsub");
|
||||
Commands.Add(new ListCommand(Db), "list");
|
||||
|
||||
Client.OnMessage += BotOnMessageReceived;
|
||||
Client.StartReceiving();
|
||||
}
|
||||
|
||||
public async Task PublishMessage(Db.Topic topic, string message)
|
||||
{
|
||||
var chatIds = await Db.GetChatIdsForTopic(topic.TopicId);
|
||||
var formatted = $"|{topic.Description}|:\n{message}";
|
||||
foreach (var c in chatIds)
|
||||
await Client.SendTextMessageAsync(c, formatted);
|
||||
}
|
||||
|
||||
async void BotOnMessageReceived(object sender, MessageEventArgs messageEventArgs)
|
||||
{
|
||||
var msg = messageEventArgs.Message;
|
||||
if (msg == null || msg.Type != MessageType.Text)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var reply = await Commands.Execute(sender, messageEventArgs);
|
||||
if (reply != null)
|
||||
await Client.SendTextMessageAsync(
|
||||
chatId: msg.Chat.Id,
|
||||
text: reply,
|
||||
replyToMessageId: msg.MessageId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.LogError(e, "Exception occured during handling of command: "+ msg.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
JetHerald/NLog.config
Normal file
27
JetHerald/NLog.config
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
autoReload="true">
|
||||
|
||||
<!-- enable asp.net core layout renderers -->
|
||||
<extensions>
|
||||
<add assembly="NLog.Web.AspNetCore"/>
|
||||
</extensions>
|
||||
|
||||
<targets>
|
||||
<target xsi:type="File" name="allfile" fileName="logs\nlog-all-${date:format=yyyy-MM-dd-HH-mm-ss}.log"
|
||||
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
|
||||
|
||||
<target name="logconsole" xsi:type="Console" />
|
||||
</targets>
|
||||
|
||||
<!-- rules to map from logger name to target -->
|
||||
<rules>
|
||||
<!--All logs, including from Microsoft-->
|
||||
<logger name="*" minlevel="Trace" writeTo="allfile" />
|
||||
<logger name="*" minlevel="Trace" writeTo="logconsole" />
|
||||
|
||||
<!--Skip non-critical Microsoft logs and so log only own logs-->
|
||||
<logger name="Microsoft.*" maxlevel="Info" final="true" />
|
||||
</rules>
|
||||
</nlog>
|
||||
49
JetHerald/Program.cs
Normal file
49
JetHerald/Program.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NLog.Web;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
|
||||
try
|
||||
{
|
||||
logger.Debug("init main");
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, "Stopped program because of exception");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
NLog.LogManager.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>()
|
||||
.ConfigureAppConfiguration(config =>
|
||||
{
|
||||
config.AddIniFile("secrets.ini");
|
||||
})
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.SetMinimumLevel(LogLevel.Trace);
|
||||
})
|
||||
.UseNLog(); // NLog: setup NLog for Dependency injection
|
||||
}
|
||||
}
|
||||
30
JetHerald/Properties/launchSettings.json
Normal file
30
JetHerald/Properties/launchSettings.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:57041",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": false,
|
||||
"launchUrl": "api/values",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"JetHerald": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": false,
|
||||
"launchUrl": "api/values",
|
||||
"applicationUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
JetHerald/Startup.cs
Normal file
43
JetHerald/Startup.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace JetHerald
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.Configure<Options.ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
|
||||
services.Configure<Options.Telegram>(Configuration.GetSection("Telegram"));
|
||||
services.AddSingleton<Db>();
|
||||
services.AddSingleton<JetHeraldBot>();
|
||||
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
|
||||
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
var bot = app.ApplicationServices.GetService<JetHeraldBot>();
|
||||
bot.Init().Wait();
|
||||
app.UsePathBase(Configuration.GetValue<string>("PathBase"));
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseMvc();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
JetHerald/appsettings.Development.json
Normal file
9
JetHerald/appsettings.Development.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
11
JetHerald/appsettings.json
Normal file
11
JetHerald/appsettings.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning"
|
||||
}
|
||||
},
|
||||
"Telegram": {
|
||||
"UseProxy": "false"
|
||||
},
|
||||
"PathBase": "/"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user