Skip to content
This repository was archived by the owner on Feb 5, 2024. It is now read-only.

Commit 8a4f4a5

Browse files
committed
Patched
0 parents  commit 8a4f4a5

30 files changed

+2336
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin/
2+
obj/

Controllers/MainHandler.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using DSharpPlus;
2+
using DSharpPlusDocs.Handlers;
3+
using System;
4+
using System.Threading.Tasks;
5+
6+
namespace DSharpPlusDocs.Controllers
7+
{
8+
public class MainHandler
9+
{
10+
public DiscordClient Client { get; private set; }
11+
12+
public CommandHandler CommandHandler { get; private set; }
13+
public QueryHandler QueryHandler { get; private set; }
14+
15+
public readonly string Prefix = "<@341606460720939008> ";
16+
17+
public MainHandler(DiscordClient client)
18+
{
19+
Client = client;
20+
CommandHandler = new CommandHandler();
21+
QueryHandler = new QueryHandler();
22+
}
23+
24+
public async Task InitializeEarlyAsync()
25+
{
26+
await CommandHandler.InitializeAsync(this);
27+
QueryHandler.Initialize();
28+
}
29+
30+
public MainHandler() => new MainHandler();
31+
}
32+
}

DSharpPlusDocs.csproj

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net6.0</TargetFramework>
4+
<DebugType>portable</DebugType>
5+
<AssemblyName>DSharpPlusDocs</AssemblyName>
6+
<OutputType>Exe</OutputType>
7+
</PropertyGroup>
8+
<ItemGroup>
9+
<PackageReference Include="DSharpPlus" Version="4.3.0-nightly-01134" />
10+
<PackageReference Include="DSharpPlus.CommandsNext" Version="4.3.0-nightly-01134" />
11+
<PackageReference Include="DSharpPlus.Interactivity" Version="4.3.0-nightly-01134" />
12+
<PackageReference Include="DSharpPlus.Rest" Version="4.3.0-nightly-01134" />
13+
<PackageReference Include="DSharpPlus.VoiceNext" Version="4.3.0-nightly-01134" />
14+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" />
15+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.2.0" />
16+
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.1" />
17+
</ItemGroup>
18+
</Project>

EmbedExtension/PaginatorBuilder.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using DSharpPlus.Entities;
2+
using System.Collections.Generic;
3+
4+
namespace DSharpPlusDocs.EmbedExtension
5+
{
6+
class PaginatorBuilder
7+
{
8+
public IEnumerable<string> Pages { get; set; }
9+
public DiscordEmbedBuilder DiscordEmbedBuilder { get; set; }
10+
}
11+
}

Handlers/CommandHandler.cs

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using DSharpPlus;
4+
using DSharpPlus.CommandsNext;
5+
using DSharpPlus.CommandsNext.Exceptions;
6+
using DSharpPlus.Entities;
7+
using DSharpPlus.EventArgs;
8+
using DSharpPlusDocs.Controllers;
9+
using DSharpPlusDocs.EmbedExtension;
10+
using DSharpPlusDocs.Modules;
11+
using DSharpPlusDocs.Paginator;
12+
using Microsoft.Extensions.Caching.Memory;
13+
using Microsoft.Extensions.DependencyInjection;
14+
15+
namespace DSharpPlusDocs.Handlers
16+
{
17+
public class CommandHandler
18+
{
19+
private CommandsNextExtension _commands;
20+
private DiscordClient _client;
21+
private MainHandler _mainHandler;
22+
private IServiceProvider _services;
23+
private MemoryCache cache = new MemoryCache(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromMinutes(3) });
24+
25+
public Task InitializeAsync(MainHandler mainHandler)
26+
{
27+
_mainHandler = mainHandler;
28+
_client = mainHandler.Client;
29+
var services = new ServiceCollection();
30+
services.AddSingleton(mainHandler);
31+
services.AddSingleton(new PaginationService(_client));
32+
_services = services.BuildServiceProvider();
33+
34+
_commands = _client.UseCommandsNext(new CommandsNextConfiguration
35+
{
36+
EnableDefaultHelp = true,
37+
Services = _services,
38+
EnableMentionPrefix = false,
39+
PrefixResolver = (x) => HandleCommand(x)
40+
});
41+
42+
_commands.SetHelpFormatter<HelpFormatter>();
43+
_commands.RegisterCommands<GeneralCommands>();
44+
45+
_client.MessageUpdated += HandleUpdate;
46+
_commands.CommandErrored += _commands_CommandErrored;
47+
48+
return Task.CompletedTask;
49+
}
50+
51+
private async Task _commands_CommandErrored(CommandsNextExtension commandsNext, CommandErrorEventArgs e)
52+
{
53+
if (e.Exception is CommandNotFoundException)
54+
{
55+
var reply = await BuildReply(e.Context.Message, e.Context.Message.Content.Substring(e.Context.Message.GetMentionPrefixLength(_client.CurrentUser)));
56+
if (reply.Item1 == null && reply.Item2 == null && reply.Item3 == null)
57+
return;
58+
DiscordMessage message;
59+
if (reply.Item3 != null)
60+
message = await e.Context.Services.GetService<PaginationService>().SendPaginatedMessageAsync(e.Context.Channel, reply.Item3);
61+
else
62+
message = await e.Context.RespondAsync(reply.Item1, embed: reply.Item2);
63+
AddCache(e.Context.Message.Id, message.Id);
64+
}
65+
else
66+
Console.WriteLine(e.Exception);
67+
}
68+
69+
public Task<int> HandleCommand(DiscordMessage msg)
70+
{
71+
if (!msg.Channel.IsPrivate && msg.Channel.Guild.Id == 81384788765712384)
72+
if (msg.Channel.Name != "dotnet_dsharpplus" && msg.Channel.Name != "testing" && msg.Channel.Name != "playground") return Task.FromResult(-1);
73+
return Task.FromResult(msg.GetMentionPrefixLength(_client.CurrentUser));
74+
}
75+
76+
private Task HandleUpdate(DiscordClient client, MessageUpdateEventArgs e)
77+
{
78+
_ = Task.Run(async () =>
79+
{
80+
ulong? id;
81+
if ((id = GetOurMessageIdFromCache(e.Message.Id)) != null)
82+
{
83+
var botMessage = await e.Channel.GetMessageAsync(id.Value);
84+
if (botMessage == null)
85+
return;
86+
int argPos = 0;
87+
if ((argPos = await HandleCommand(e.Message)) == -1) return;
88+
var reply = await BuildReply(e.Message, e.Message.Content.Substring(argPos));
89+
90+
if (reply.Item1 == null && reply.Item2 == null && reply.Item3 == null)
91+
return;
92+
var pagination = _services.GetService<PaginationService>();
93+
var isPaginatedMessage = pagination.IsPaginatedMessage(id.Value);
94+
if (reply.Item3 != null)
95+
{
96+
if (isPaginatedMessage)
97+
await pagination.UpdatePaginatedMessageAsync(botMessage, reply.Item3);
98+
else
99+
await pagination.EditMessageToPaginatedMessageAsync(botMessage, reply.Item3);
100+
}
101+
else
102+
{
103+
if (isPaginatedMessage)
104+
{
105+
pagination.StopTrackingPaginatedMessage(id.Value);
106+
_ = botMessage.DeleteAllReactionsAsync(); //TODO: Should await, but D#+ is broken
107+
}
108+
await botMessage.ModifyAsync(reply.Item1, reply.Item2.Build());
109+
}
110+
}
111+
});
112+
return Task.CompletedTask;
113+
}
114+
115+
private async Task<(string, DiscordEmbedBuilder, PaginatedMessage)> BuildReply(DiscordMessage msg, string message)
116+
{
117+
if (!_mainHandler.QueryHandler.IsReady())
118+
{
119+
return ("Loading cache...", null, null); //TODO: Change message
120+
}
121+
else
122+
{
123+
try
124+
{
125+
var tuple = await _mainHandler.QueryHandler.RunAsync(message);
126+
if (tuple.Item2 is PaginatorBuilder pag)
127+
{
128+
var paginated = new PaginatedMessage(pag.Pages, "Results", user: msg.Author, options: new AppearanceOptions { Timeout = TimeSpan.FromMinutes(10) });
129+
return (null, null, paginated);
130+
}
131+
else
132+
return (tuple.Item1, tuple.Item2 as DiscordEmbedBuilder, null);
133+
}
134+
catch (Exception e)
135+
{
136+
Console.WriteLine(e.ToString());
137+
return ("Uh-oh... I think some pipes have broken...", null, null);
138+
}
139+
}
140+
}
141+
142+
public void AddCache(ulong userMessageId, ulong ourMessageId)
143+
{
144+
cache.Set(userMessageId, ourMessageId, new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) });
145+
}
146+
147+
public ulong? GetOurMessageIdFromCache(ulong messageId)
148+
{
149+
if (cache.TryGetValue(messageId, out ulong id))
150+
return id;
151+
return null;
152+
}
153+
154+
/*public async Task<DiscordEmbed> HelpEmbedBuilderAsync(CommandContext context, string command = null)
155+
{
156+
DiscordEmbed eb = new DiscordEmbed();
157+
eb.Author = new DiscordEmbedAuthor().WithName("Help:").WithIconUrl("http://i.imgur.com/VzDRjUn.png");
158+
StringBuilder sb = new StringBuilder();
159+
if (command == null)
160+
{
161+
foreach (ModuleInfo mi in _commands.Modules.OrderBy(x => x.Name))
162+
if (!mi.IsSubmodule)
163+
if (mi.Name != "Help")
164+
{
165+
bool ok = true;
166+
foreach (PreconditionAttribute precondition in mi.Preconditions)
167+
if (!(await precondition.CheckPermissions(context, null, _services)).IsSuccess)
168+
{
169+
ok = false;
170+
break;
171+
}
172+
if (ok)
173+
{
174+
var cmds = mi.Commands.ToList<object>();
175+
cmds.AddRange(mi.Submodules);
176+
for (int i = cmds.Count - 1; i >= 0; i--)
177+
{
178+
object o = cmds[i];
179+
foreach (PreconditionAttribute precondition in ((o as CommandInfo)?.Preconditions ?? (o as ModuleInfo)?.Preconditions))
180+
if (!(await precondition.CheckPermissions(context, o as CommandInfo, _services)).IsSuccess)
181+
cmds.Remove(o);
182+
}
183+
if (cmds.Count != 0)
184+
{
185+
var list = cmds.Select(x => $"{((x as CommandInfo)?.Name ?? (x as ModuleInfo)?.Name)}").OrderBy(x => x);
186+
sb.AppendLine($"**{mi.Name}:** {String.Join(", ", list)}");
187+
}
188+
}
189+
}
190+
191+
eb.AddField((x) =>
192+
{
193+
x.IsInline = false;
194+
x.Name = "Query help";
195+
x.Value = $"Usage: {context.Client.CurrentUser.Mention} [query]";
196+
});
197+
eb.AddField((x) =>
198+
{
199+
x.IsInline = true;
200+
x.Name = "Keywords";
201+
x.Value = "method, type, property,\nevent, in, list";
202+
});
203+
eb.AddField((x) =>
204+
{
205+
x.IsInline = true;
206+
x.Name = "Examples";
207+
x.Value = "EmbedBuilder\n" +
208+
"IGuildUser.Nickname\n" +
209+
"ModifyAsync in IRole\n" +
210+
"send message\n" +
211+
"type Emote";
212+
});
213+
eb.Footer = new EmbedFooterBuilder().WithText("Note: (i) = Inherited");
214+
eb.Description = sb.ToString();
215+
}
216+
else
217+
{
218+
SearchResult sr = _commands.Search(context, command);
219+
if (sr.IsSuccess)
220+
{
221+
Nullable<CommandMatch> cmd = null;
222+
if (sr.Commands.Count == 1)
223+
cmd = sr.Commands.First();
224+
else
225+
{
226+
int lastIndex;
227+
var find = sr.Commands.Where(x => x.Command.Aliases.First().Equals(command, StringComparison.OrdinalIgnoreCase));
228+
if (find.Any())
229+
cmd = find.First();
230+
while (cmd == null && (lastIndex = command.LastIndexOf(' ')) != -1) //TODO: Maybe remove and say command not found?
231+
{
232+
find = sr.Commands.Where(x => x.Command.Aliases.First().Equals(command.Substring(0, lastIndex), StringComparison.OrdinalIgnoreCase));
233+
if (find.Any())
234+
cmd = find.First();
235+
command = command.Substring(0, lastIndex);
236+
}
237+
}
238+
if (cmd != null && (await cmd.Value.CheckPreconditionsAsync(context, _services)).IsSuccess)
239+
{
240+
eb.Author.Name = $"Help: {cmd.Value.Command.Aliases.First()}";
241+
sb.Append($"Usage: {_mainHandler.Prefix}{cmd.Value.Command.Aliases.First()}");
242+
if (cmd.Value.Command.Parameters.Count != 0)
243+
sb.Append($" [{String.Join("] [", cmd.Value.Command.Parameters.Select(x => x.Name))}]");
244+
if (!String.IsNullOrEmpty(cmd.Value.Command.Summary))
245+
sb.Append($"\nSummary: {cmd.Value.Command.Summary}");
246+
if (!String.IsNullOrEmpty(cmd.Value.Command.Remarks))
247+
sb.Append($"\nRemarks: {cmd.Value.Command.Remarks}");
248+
if (cmd.Value.Command.Aliases.Count != 1)
249+
sb.Append($"\nAliases: {String.Join(", ", cmd.Value.Command.Aliases.Where(x => x != cmd.Value.Command.Aliases.First()))}");
250+
eb.Description = sb.ToString();
251+
}
252+
else
253+
eb.Description = $"Command '{command}' not found.";
254+
}
255+
else
256+
eb.Description = $"Command '{command}' not found.";
257+
}
258+
return eb;
259+
}*/
260+
}
261+
}

Handlers/QueryHandler.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System.Threading.Tasks;
2+
using DSharpPlus.Entities;
3+
using DSharpPlusDocs.Query;
4+
using DSharpPlusDocs.Query.Results;
5+
6+
namespace DSharpPlusDocs.Handlers
7+
{
8+
public class QueryHandler
9+
{
10+
public Cache Cache { get; private set; }
11+
public static string DocsBaseUrl { get; set; } = "https://dsharpplus.emzi0767.com/";
12+
13+
public QueryHandler()
14+
{
15+
Cache = new Cache();
16+
}
17+
18+
public void Initialize()
19+
{
20+
Cache.Initialize();
21+
}
22+
23+
public async Task<(string, object)> RunAsync(string text)
24+
{
25+
var interpreterResult = new TextInterpreter(text).Run();
26+
if (!interpreterResult.IsSuccess)
27+
return ($"{interpreterResult.Error}", null);
28+
29+
object result;
30+
if (interpreterResult.Search == SearchType.JUST_NAMESPACE)
31+
result = await SearchAsync(interpreterResult, SearchType.NONE) ?? await SearchAsync(interpreterResult, SearchType.JUST_NAMESPACE) ?? await SearchAsync(interpreterResult, SearchType.JUST_TEXT) ?? await SearchAsync(interpreterResult, SearchType.ALL);
32+
else
33+
result = await SearchAsync(interpreterResult, SearchType.NONE) ?? await SearchAsync(interpreterResult, SearchType.JUST_TEXT) ?? await SearchAsync(interpreterResult, SearchType.JUST_NAMESPACE) ?? await SearchAsync(interpreterResult, SearchType.ALL);
34+
35+
return result == null ? ($"No results found for `{text}`.", null) : ("", result);
36+
}
37+
38+
private async Task<object> SearchAsync(InterpreterResult interpreterResult, SearchType type)
39+
{
40+
interpreterResult.Search = type;
41+
var searchResult = new Search(interpreterResult, Cache).Run();
42+
if (searchResult.Count != 0)
43+
return await new ResultDisplay(searchResult, Cache, interpreterResult.IsList).RunAsync();
44+
return null;
45+
}
46+
47+
public bool IsReady()
48+
{
49+
return Cache.IsReady();
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)