Port more things!
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Myriad.Gateway;
|
||||
using Myriad.Rest;
|
||||
using Myriad.Types;
|
||||
|
||||
namespace Myriad.Cache
|
||||
{
|
||||
@@ -29,7 +31,7 @@ namespace Myriad.Cache
|
||||
case GuildRoleDeleteEvent grd:
|
||||
return cache.RemoveRole(grd.GuildId, grd.RoleId);
|
||||
case MessageCreateEvent mc:
|
||||
return cache.SaveUser(mc.Author);
|
||||
return cache.SaveMessageCreate(mc);
|
||||
}
|
||||
|
||||
return default;
|
||||
@@ -46,5 +48,23 @@ namespace Myriad.Cache
|
||||
foreach (var member in guildCreate.Members)
|
||||
await cache.SaveUser(member.User);
|
||||
}
|
||||
|
||||
private static async ValueTask SaveMessageCreate(this IDiscordCache cache, MessageCreateEvent evt)
|
||||
{
|
||||
await cache.SaveUser(evt.Author);
|
||||
foreach (var mention in evt.Mentions)
|
||||
await cache.SaveUser(mention);
|
||||
}
|
||||
|
||||
public static async ValueTask<User?> GetOrFetchUser(this IDiscordCache cache, DiscordApiClient rest, ulong userId)
|
||||
{
|
||||
if (cache.TryGetUser(userId, out var cacheUser))
|
||||
return cacheUser;
|
||||
|
||||
var restUser = await rest.GetUser(userId);
|
||||
if (restUser != null)
|
||||
await cache.SaveUser(restUser);
|
||||
return restUser;
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,7 +6,7 @@ namespace Myriad.Extensions
|
||||
{
|
||||
public static string Mention(this User user) => $"<@{user.Id}>";
|
||||
|
||||
public static string AvatarUrl(this User user) =>
|
||||
$"https://cdn.discordapp.com/avatars/{user.Id}/{user.Avatar}.png";
|
||||
public static string AvatarUrl(this User user, string? format = "png", int? size = 128) =>
|
||||
$"https://cdn.discordapp.com/avatars/{user.Id}/{user.Avatar}.{format}?size={size}";
|
||||
}
|
||||
}
|
@@ -27,6 +27,7 @@ namespace Myriad.Gateway
|
||||
public IReadOnlyDictionary<int, Shard> Shards => _shards;
|
||||
public ClusterSessionState SessionState => GetClusterState();
|
||||
public User? User => _shards.Values.Select(s => s.User).FirstOrDefault(s => s != null);
|
||||
public ApplicationPartial? Application => _shards.Values.Select(s => s.Application).FirstOrDefault(s => s != null);
|
||||
|
||||
private ClusterSessionState GetClusterState()
|
||||
{
|
||||
|
@@ -32,6 +32,7 @@ namespace Myriad.Gateway
|
||||
public ShardState State { get; private set; }
|
||||
public TimeSpan? Latency { get; private set; }
|
||||
public User? User { get; private set; }
|
||||
public ApplicationPartial? Application { get; private set; }
|
||||
|
||||
public Func<IGatewayEvent, Task>? OnEventReceived { get; set; }
|
||||
|
||||
@@ -258,6 +259,7 @@ namespace Myriad.Gateway
|
||||
ShardInfo = ready.Shard;
|
||||
SessionInfo = SessionInfo with { Session = ready.SessionId };
|
||||
User = ready.User;
|
||||
Application = ready.Application;
|
||||
State = ShardState.Open;
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
@@ -33,8 +33,11 @@ namespace Myriad.Rest
|
||||
public Task<Message?> GetMessage(ulong channelId, ulong messageId) =>
|
||||
_client.Get<Message>($"/channels/{channelId}/messages/{messageId}", ("GetMessage", channelId));
|
||||
|
||||
public Task<Channel?> GetGuild(ulong id) =>
|
||||
_client.Get<Channel>($"/guilds/{id}", ("GetGuild", id));
|
||||
public Task<Guild?> GetGuild(ulong id) =>
|
||||
_client.Get<Guild>($"/guilds/{id}", ("GetGuild", id));
|
||||
|
||||
public Task<Channel[]> GetGuildChannels(ulong id) =>
|
||||
_client.Get<Channel[]>($"/guilds/{id}/channels", ("GetGuildChannels", id))!;
|
||||
|
||||
public Task<User?> GetUser(ulong id) =>
|
||||
_client.Get<User>($"/users/{id}", ("GetUser", default));
|
||||
|
@@ -77,8 +77,8 @@ namespace Myriad.Rest.Ratelimit
|
||||
var headerNextReset = DateTimeOffset.UtcNow + headers.ResetAfter.Value; // todo: server time
|
||||
if (headerNextReset > _nextReset)
|
||||
{
|
||||
_logger.Debug("{BucketKey}/{BucketMajor}: Received reset time {NextReset} from server",
|
||||
Key, Major, _nextReset);
|
||||
_logger.Debug("{BucketKey}/{BucketMajor}: Received reset time {NextReset} from server (after: {NextResetAfter})",
|
||||
Key, Major, headerNextReset, headers.ResetAfter.Value);
|
||||
|
||||
_nextReset = headerNextReset;
|
||||
_resetTimeValid = true;
|
||||
@@ -101,7 +101,7 @@ namespace Myriad.Rest.Ratelimit
|
||||
_semaphore.Wait();
|
||||
|
||||
// If we're past the reset time *and* we haven't reset already, do that
|
||||
var timeSinceReset = _nextReset - now;
|
||||
var timeSinceReset = now - _nextReset;
|
||||
var shouldReset = _resetTimeValid && timeSinceReset > TimeSpan.Zero;
|
||||
if (shouldReset)
|
||||
{
|
||||
|
@@ -1,10 +1,22 @@
|
||||
using Myriad.Types;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Myriad.Types;
|
||||
using Myriad.Utils;
|
||||
|
||||
namespace Myriad.Rest.Types.Requests
|
||||
{
|
||||
public record MessageEditRequest
|
||||
{
|
||||
public string? Content { get; set; }
|
||||
public Embed? Embed { get; set; }
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Optional<string?> Content { get; init; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Optional<Embed?> Embed { get; init; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Optional<Message.MessageFlags> Flags { get; init; }
|
||||
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Optional<AllowedMentions> AllowedMentions { get; init; }
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ namespace Myriad.Rest.Types.Requests
|
||||
public string? Content { get; set; }
|
||||
public object? Nonce { get; set; }
|
||||
public bool Tts { get; set; }
|
||||
public AllowedMentions AllowedMentions { get; set; }
|
||||
public AllowedMentions? AllowedMentions { get; set; }
|
||||
public Embed? Embed { get; set; }
|
||||
}
|
||||
}
|
43
Myriad/Serialization/OptionalConverter.cs
Normal file
43
Myriad/Serialization/OptionalConverter.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Myriad.Utils;
|
||||
|
||||
namespace Myriad.Serialization
|
||||
{
|
||||
public class OptionalConverter: JsonConverter<IOptional>
|
||||
{
|
||||
public override IOptional? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var innerType = typeToConvert.GetGenericArguments()[0];
|
||||
var inner = JsonSerializer.Deserialize(ref reader, innerType, options);
|
||||
|
||||
// TODO: rewrite to JsonConverterFactory to cut down on reflection
|
||||
return (IOptional?) Activator.CreateInstance(
|
||||
typeof(Optional<>).MakeGenericType(innerType),
|
||||
BindingFlags.Instance | BindingFlags.Public,
|
||||
null,
|
||||
new[] {inner},
|
||||
null);
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, IOptional value, JsonSerializerOptions options)
|
||||
{
|
||||
var innerType = value.GetType().GetGenericArguments()[0];
|
||||
JsonSerializer.Serialize(writer, value.GetValue(), innerType, options);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
{
|
||||
if (!typeToConvert.IsGenericType)
|
||||
return false;
|
||||
|
||||
if (typeToConvert.GetGenericTypeDefinition() != typeof(Optional<>))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
32
Myriad/Utils/Optional.cs
Normal file
32
Myriad/Utils/Optional.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Myriad.Serialization;
|
||||
|
||||
namespace Myriad.Utils
|
||||
{
|
||||
public interface IOptional
|
||||
{
|
||||
bool HasValue { get; }
|
||||
object? GetValue();
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(OptionalConverter))]
|
||||
public readonly struct Optional<T>: IOptional
|
||||
{
|
||||
public Optional(T value)
|
||||
{
|
||||
HasValue = true;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public bool HasValue { get; }
|
||||
public object? GetValue() => Value;
|
||||
|
||||
public T Value { get; }
|
||||
|
||||
public static implicit operator Optional<T>(T value) => new(value);
|
||||
|
||||
public static Optional<T> Some(T value) => new(value);
|
||||
public static Optional<T> None() => default;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user