feat(client): add rendezvous traversal coordinators (#12)
quality-gate / quality (push) Successful in 56s
quality-gate / quality (push) Successful in 56s
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
using System.Text;
|
||||
using FinalFactory.Rendezvous.Contracts;
|
||||
|
||||
namespace FinalFactory.Rendezvous.Client;
|
||||
|
||||
public sealed class DirectConnectionRequest
|
||||
{
|
||||
public JoinAttemptId AttemptId { get; set; }
|
||||
public string ConnectionTicket { get; set; } = string.Empty;
|
||||
|
||||
public override string ToString() =>
|
||||
$"[DirectConnectionRequest {AttemptId}; ticket redacted]";
|
||||
}
|
||||
|
||||
public static class DirectConnectionRequestCodec
|
||||
{
|
||||
public const int EncodedLength = 63;
|
||||
|
||||
private const int MagicLength = 4;
|
||||
private const int AttemptIdLength = 16;
|
||||
private const int TicketLength = ContractLimits.DerivedCredentialCharacters;
|
||||
private static readonly byte[] Magic = [(byte)'R', (byte)'V', (byte)'D', (byte)'1'];
|
||||
|
||||
public static bool IsRendezvousRequest(ReadOnlySpan<byte> encoded) =>
|
||||
encoded.Length >= MagicLength && encoded[..MagicLength].SequenceEqual(Magic);
|
||||
|
||||
public static byte[] Encode(JoinAttemptId attemptId, string connectionTicket)
|
||||
{
|
||||
if (attemptId.Value == Guid.Empty
|
||||
|| connectionTicket is null
|
||||
|| connectionTicket.Length != TicketLength
|
||||
|| !ContractValidation.IsConnectionTicketValid(connectionTicket))
|
||||
{
|
||||
throw new ArgumentException("The direct connection request fields are invalid.");
|
||||
}
|
||||
|
||||
byte[] encoded = new byte[EncodedLength];
|
||||
Magic.CopyTo(encoded, 0);
|
||||
if (!attemptId.Value.TryWriteBytes(encoded.AsSpan(MagicLength, AttemptIdLength)))
|
||||
{
|
||||
throw new InvalidOperationException("The join attempt identifier could not be encoded.");
|
||||
}
|
||||
|
||||
Encoding.ASCII.GetBytes(
|
||||
connectionTicket,
|
||||
0,
|
||||
connectionTicket.Length,
|
||||
encoded,
|
||||
MagicLength + AttemptIdLength);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
public static bool TryDecode(
|
||||
ReadOnlySpan<byte> encoded,
|
||||
out DirectConnectionRequest? request)
|
||||
{
|
||||
request = null;
|
||||
if (encoded.Length != EncodedLength
|
||||
|| !encoded[..MagicLength].SequenceEqual(Magic))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Guid attemptId = new(encoded.Slice(MagicLength, AttemptIdLength));
|
||||
if (attemptId == Guid.Empty)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string ticket = Encoding.ASCII.GetString(encoded[(MagicLength + AttemptIdLength)..]);
|
||||
if (!ContractValidation.IsConnectionTicketValid(ticket))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
request = new DirectConnectionRequest
|
||||
{
|
||||
AttemptId = new JoinAttemptId(attemptId),
|
||||
ConnectionTicket = ticket,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user