Merge branch 'release/1.3.1' into main

This commit is contained in:
Oliver Booth 2023-08-27 21:45:29 +01:00
commit 1f57ecca06
Signed by: oliverbooth
GPG Key ID: B89D139977693FED
4 changed files with 88 additions and 9 deletions

View File

@ -1,5 +1,4 @@
using Cysharp.Text; using Cysharp.Text;
using Humanizer;
namespace VPLink.Common.Data; namespace VPLink.Common.Data;
@ -35,13 +34,12 @@ public struct PlainTextMessageBuilder : IDisposable
/// <param name="timestamp">The timestamp.</param> /// <param name="timestamp">The timestamp.</param>
/// <param name="format">The format.</param> /// <param name="format">The format.</param>
/// <param name="whitespace">The trailing whitespace trivia.</param> /// <param name="whitespace">The trailing whitespace trivia.</param>
public void AddTimestamp(DateTimeOffset timestamp, TimestampFormat format = TimestampFormat.None, public void AddTimestamp(DateTimeOffset timestamp, TimestampFormat format, char whitespace = ' ')
char whitespace = ' ')
{ {
switch (format) switch (format)
{ {
case TimestampFormat.Relative: case TimestampFormat.Relative:
AddWord(timestamp.Humanize(), whitespace); AddWord(FormatRelativeTime(timestamp), whitespace);
break; break;
case TimestampFormat.None: case TimestampFormat.None:
@ -104,4 +102,53 @@ public struct PlainTextMessageBuilder : IDisposable
{ {
return _builder.ToString().Trim(); return _builder.ToString().Trim();
} }
private static string FormatRelativeTime(DateTimeOffset targetTime)
{
TimeSpan timeDifference = DateTimeOffset.Now - targetTime;
bool isFuture = timeDifference.TotalMilliseconds < 0;
int value;
string unit;
timeDifference = TimeSpan.FromMilliseconds(Math.Abs(timeDifference.TotalMilliseconds));
switch (timeDifference.TotalDays)
{
case >= 365:
unit = "year";
value = (int)(timeDifference.TotalDays / 365);
break;
case >= 30:
unit = "month";
value = (int)(timeDifference.TotalDays / 30);
break;
case >= 1:
unit = "day";
value = (int)timeDifference.TotalDays;
break;
default:
if (timeDifference.TotalHours >= 1)
{
unit = "hour";
value = (int)timeDifference.TotalHours;
}
else if (timeDifference.TotalMinutes >= 1)
{
unit = "minute";
value = (int)timeDifference.TotalMinutes;
}
else
{
unit = "second";
value = (int)timeDifference.TotalSeconds;
}
break;
}
string suffix = value > 1 ? "s" : "";
return isFuture ? $"in {value} {unit}{suffix}" : $"{value} {unit}{suffix} ago";
}
} }

View File

@ -24,6 +24,11 @@ public static class MentionUtility
else else
switch (contents[0]) switch (contents[0])
{ {
// custom emote
case ':':
ParseCustomEmote(contents, ref builder, whitespaceTrivia);
break;
// user mention // user mention
case '@': case '@':
ParseUserMention(guild, contents, ref builder, whitespaceTrivia); ParseUserMention(guild, contents, ref builder, whitespaceTrivia);
@ -71,6 +76,15 @@ public static class MentionUtility
whitespaceTrivia); whitespaceTrivia);
} }
private static void ParseCustomEmote(ReadOnlySpan<char> contents,
ref PlainTextMessageBuilder builder,
char whitespaceTrivia)
{
contents = contents[1..];
ReadOnlySpan<char> name = contents[..contents.IndexOf(':')];
builder.AddWord($":{name.ToString()}:", whitespaceTrivia);
}
private static void ParseTimestamp(ReadOnlySpan<char> contents, private static void ParseTimestamp(ReadOnlySpan<char> contents,
ref PlainTextMessageBuilder builder, ref PlainTextMessageBuilder builder,
char whitespaceTrivia) char whitespaceTrivia)

View File

@ -96,6 +96,9 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage
SanitizeContent(guild, message.Content, ref builder); SanitizeContent(guild, message.Content, ref builder);
var content = builder.ToString(); var content = builder.ToString();
Span<byte> testSpan = stackalloc byte[Utf8Encoding.GetByteCount(content)];
Utf8Encoding.GetBytes(content, testSpan);
_logger.LogInformation("Message by {Author}: {Content}", author, content); _logger.LogInformation("Message by {Author}: {Content}", author, content);
var messages = new List<RelayedMessage>(); var messages = new List<RelayedMessage>();
@ -141,14 +144,16 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage
private static void AddMessage(ICollection<RelayedMessage> messages, string displayName, string content) private static void AddMessage(ICollection<RelayedMessage> messages, string displayName, string content)
{ {
Span<byte> buffer = stackalloc byte[255]; // VP message length limit
int byteCount = Utf8Encoding.GetByteCount(content); int byteCount = Utf8Encoding.GetByteCount(content);
Span<byte> buffer = stackalloc byte[byteCount];
Utf8Encoding.GetBytes(content, buffer);
var offset = 0; var offset = 0;
while (offset < byteCount) while (offset < byteCount)
{ {
int length = Math.Min(byteCount - offset, 255); int length = Math.Min(byteCount - offset, 255); // VP message length limit
Utf8Encoding.GetBytes(content.AsSpan(offset, length), buffer); Span<byte> slice = buffer.Slice(offset, length);
messages.Add(new RelayedMessage(displayName, Utf8Encoding.GetString(buffer), false)); messages.Add(new RelayedMessage(displayName, Utf8Encoding.GetString(slice), false));
offset += length; offset += length;
} }
} }
@ -199,6 +204,8 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage
{ {
Utf8ValueStringBuilder wordBuffer = ZString.CreateUtf8StringBuilder(); Utf8ValueStringBuilder wordBuffer = ZString.CreateUtf8StringBuilder();
Span<char> chars = stackalloc char[2];
Span<byte> bytes = stackalloc byte[4];
for (var index = 0; index < content.Length; index++) for (var index = 0; index < content.Length; index++)
{ {
char current = content[index]; char current = content[index];
@ -207,6 +214,13 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage
AddWord(guild, ref builder, ref wordBuffer, current); AddWord(guild, ref builder, ref wordBuffer, current);
wordBuffer.Clear(); wordBuffer.Clear();
} }
else if (char.IsSurrogate(current))
{
content.Slice(index++, 2).CopyTo(chars);
int byteCount = Utf8Encoding.GetByteCount(chars);
Utf8Encoding.GetBytes(chars, bytes);
wordBuffer.AppendLiteral(bytes[..byteCount]);
}
else else
{ {
wordBuffer.Append(current); wordBuffer.Append(current);
@ -256,6 +270,10 @@ internal sealed class DiscordMessageService : BackgroundService, IDiscordMessage
MentionUtility.ParseTag(guild, temp[..tagLength], ref builder, whitespace); MentionUtility.ParseTag(guild, temp[..tagLength], ref builder, whitespace);
break; break;
case var _ when char.IsSurrogate(current):
buffer.Append(chars.Slice(index++, 2));
break;
default: default:
buffer.Append(current); buffer.Append(current);
break; break;

View File

@ -9,7 +9,7 @@
<Authors>Oliver Booth</Authors> <Authors>Oliver Booth</Authors>
<RepositoryUrl>https://github.com/oliverbooth/VpBridge</RepositoryUrl> <RepositoryUrl>https://github.com/oliverbooth/VpBridge</RepositoryUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<VersionPrefix>1.3.0</VersionPrefix> <VersionPrefix>1.3.1</VersionPrefix>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'"> <PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">