Initial mirror.

This commit is contained in:
2025-08-22 01:55:30 +01:00
commit 7729d6b0d7
65 changed files with 1609 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
using MareSynchronos.API.Data.Enum;
using MessagePack;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Text;
using System.Security.Cryptography;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public class CharacterData
{
public CharacterData()
{
DataHash = new(() =>
{
var json = JsonSerializer.Serialize(this);
#pragma warning disable SYSLIB0021 // Type or member is obsolete
using SHA256CryptoServiceProvider cryptoProvider = new();
#pragma warning restore SYSLIB0021 // Type or member is obsolete
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(json))).Replace("-", "", StringComparison.Ordinal);
});
}
public Dictionary<ObjectKind, string> CustomizePlusData { get; set; } = new();
[JsonIgnore]
public Lazy<string> DataHash { get; }
public Dictionary<ObjectKind, List<FileReplacementData>> FileReplacements { get; set; } = new();
public Dictionary<ObjectKind, string> GlamourerData { get; set; } = new();
public string HeelsData { get; set; } = string.Empty;
public string HonorificData { get; set; } = string.Empty;
public string ManipulationData { get; set; } = string.Empty;
public string MoodlesData { get; set; } = string.Empty;
public string PetNamesData { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,11 @@
using MessagePack;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public record ChatMessage
{
public string SenderName { get; set; } = string.Empty;
public uint SenderHomeWorldId { get; set; } = 0;
public byte[] PayloadContent { get; set; } = [];
}

View File

@@ -0,0 +1,19 @@
namespace MareSynchronos.API.Data.Comparer;
public class GroupDataComparer : IEqualityComparer<GroupData>
{
public static GroupDataComparer Instance => _instance;
private static GroupDataComparer _instance = new GroupDataComparer();
private GroupDataComparer() { }
public bool Equals(GroupData? x, GroupData? y)
{
if (x == null || y == null) return false;
return x.GID.Equals(y.GID, StringComparison.Ordinal);
}
public int GetHashCode(GroupData obj)
{
return obj.GID.GetHashCode();
}
}

View File

@@ -0,0 +1,23 @@
using MareSynchronos.API.Dto.Group;
namespace MareSynchronos.API.Data.Comparer;
public class GroupDtoComparer : IEqualityComparer<GroupDto>
{
public static GroupDtoComparer Instance => _instance;
private static GroupDtoComparer _instance = new GroupDtoComparer();
private GroupDtoComparer() { }
public bool Equals(GroupDto? x, GroupDto? y)
{
if (x == null || y == null) return false;
return x.GID.Equals(y.GID, StringComparison.Ordinal);
}
public int GetHashCode(GroupDto obj)
{
return obj.Group.GID.GetHashCode();
}
}

View File

@@ -0,0 +1,20 @@
using MareSynchronos.API.Dto.Group;
namespace MareSynchronos.API.Data.Comparer;
public class GroupPairDtoComparer : IEqualityComparer<GroupPairDto>
{
public static GroupPairDtoComparer Instance => _instance;
private static GroupPairDtoComparer _instance = new();
private GroupPairDtoComparer() { }
public bool Equals(GroupPairDto? x, GroupPairDto? y)
{
if (x == null || y == null) return false;
return x.GID.Equals(y.GID, StringComparison.Ordinal) && x.UID.Equals(y.UID, StringComparison.Ordinal);
}
public int GetHashCode(GroupPairDto obj)
{
return HashCode.Combine(obj.Group.GID.GetHashCode(), obj.User.UID.GetHashCode());
}
}

View File

@@ -0,0 +1,20 @@
namespace MareSynchronos.API.Data.Comparer;
public class UserDataComparer : IEqualityComparer<UserData>
{
public static UserDataComparer Instance => _instance;
private static UserDataComparer _instance = new();
private UserDataComparer() { }
public bool Equals(UserData? x, UserData? y)
{
if (x == null || y == null) return false;
return x.UID.Equals(y.UID, StringComparison.Ordinal);
}
public int GetHashCode(UserData obj)
{
return obj.UID.GetHashCode();
}
}

View File

@@ -0,0 +1,20 @@
using MareSynchronos.API.Dto.User;
namespace MareSynchronos.API.Data.Comparer;
public class UserDtoComparer : IEqualityComparer<UserDto>
{
public static UserDtoComparer Instance => _instance;
private static UserDtoComparer _instance = new();
private UserDtoComparer() { }
public bool Equals(UserDto? x, UserDto? y)
{
if (x == null || y == null) return false;
return x.User.UID.Equals(y.User.UID, StringComparison.Ordinal);
}
public int GetHashCode(UserDto obj)
{
return obj.User.UID.GetHashCode();
}
}

View File

@@ -0,0 +1,11 @@
namespace MareSynchronos.API.Data.Enum;
[Flags]
public enum GroupPermissions
{
NoneSet = 0x0,
DisableAnimations = 0x1,
DisableSounds = 0x2,
DisableInvites = 0x4,
DisableVFX = 0x8,
}

View File

@@ -0,0 +1,9 @@
namespace MareSynchronos.API.Data.Enum;
[Flags]
public enum GroupUserInfo
{
None = 0x0,
IsModerator = 0x2,
IsPinned = 0x4
}

View File

@@ -0,0 +1,11 @@
namespace MareSynchronos.API.Data.Enum;
[Flags]
public enum GroupUserPermissions
{
NoneSet = 0x0,
Paused = 0x1,
DisableAnimations = 0x2,
DisableSounds = 0x4,
DisableVFX = 0x8,
}

View File

@@ -0,0 +1,8 @@
namespace MareSynchronos.API.Data.Enum;
public enum MessageSeverity
{
Information,
Warning,
Error
}

View File

@@ -0,0 +1,9 @@
namespace MareSynchronos.API.Data.Enum;
public enum ObjectKind
{
Player = 0,
MinionOrMount = 1,
Companion = 2,
Pet = 3,
}

View File

@@ -0,0 +1,12 @@
namespace MareSynchronos.API.Data.Enum;
[Flags]
public enum UserPermissions
{
NoneSet = 0,
Paired = 1,
Paused = 2,
DisableAnimations = 4,
DisableSounds = 8,
DisableVFX = 16,
}

View File

@@ -0,0 +1,50 @@
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.API.Data.Extensions;
public static class GroupPermissionsExtensions
{
public static bool IsDisableAnimations(this GroupPermissions perm)
{
return perm.HasFlag(GroupPermissions.DisableAnimations);
}
public static bool IsDisableSounds(this GroupPermissions perm)
{
return perm.HasFlag(GroupPermissions.DisableSounds);
}
public static bool IsDisableInvites(this GroupPermissions perm)
{
return perm.HasFlag(GroupPermissions.DisableInvites);
}
public static bool IsDisableVFX(this GroupPermissions perm)
{
return perm.HasFlag(GroupPermissions.DisableVFX);
}
public static void SetDisableAnimations(this ref GroupPermissions perm, bool set)
{
if (set) perm |= GroupPermissions.DisableAnimations;
else perm &= ~GroupPermissions.DisableAnimations;
}
public static void SetDisableSounds(this ref GroupPermissions perm, bool set)
{
if (set) perm |= GroupPermissions.DisableSounds;
else perm &= ~GroupPermissions.DisableSounds;
}
public static void SetDisableInvites(this ref GroupPermissions perm, bool set)
{
if (set) perm |= GroupPermissions.DisableInvites;
else perm &= ~GroupPermissions.DisableInvites;
}
public static void SetDisableVFX(this ref GroupPermissions perm, bool set)
{
if (set) perm |= GroupPermissions.DisableVFX;
else perm &= ~GroupPermissions.DisableVFX;
}
}

View File

@@ -0,0 +1,28 @@
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.API.Data.Extensions;
public static class GroupUserInfoExtensions
{
public static bool IsModerator(this GroupUserInfo info)
{
return info.HasFlag(GroupUserInfo.IsModerator);
}
public static bool IsPinned(this GroupUserInfo info)
{
return info.HasFlag(GroupUserInfo.IsPinned);
}
public static void SetModerator(this ref GroupUserInfo info, bool isModerator)
{
if (isModerator) info |= GroupUserInfo.IsModerator;
else info &= ~GroupUserInfo.IsModerator;
}
public static void SetPinned(this ref GroupUserInfo info, bool isPinned)
{
if (isPinned) info |= GroupUserInfo.IsPinned;
else info &= ~GroupUserInfo.IsPinned;
}
}

View File

@@ -0,0 +1,50 @@
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.API.Data.Extensions;
public static class GroupUserPermissionsExtensions
{
public static bool IsDisableAnimations(this GroupUserPermissions perm)
{
return perm.HasFlag(GroupUserPermissions.DisableAnimations);
}
public static bool IsDisableSounds(this GroupUserPermissions perm)
{
return perm.HasFlag(GroupUserPermissions.DisableSounds);
}
public static bool IsPaused(this GroupUserPermissions perm)
{
return perm.HasFlag(GroupUserPermissions.Paused);
}
public static bool IsDisableVFX(this GroupUserPermissions perm)
{
return perm.HasFlag(GroupUserPermissions.DisableVFX);
}
public static void SetDisableAnimations(this ref GroupUserPermissions perm, bool set)
{
if (set) perm |= GroupUserPermissions.DisableAnimations;
else perm &= ~GroupUserPermissions.DisableAnimations;
}
public static void SetDisableSounds(this ref GroupUserPermissions perm, bool set)
{
if (set) perm |= GroupUserPermissions.DisableSounds;
else perm &= ~GroupUserPermissions.DisableSounds;
}
public static void SetPaused(this ref GroupUserPermissions perm, bool set)
{
if (set) perm |= GroupUserPermissions.Paused;
else perm &= ~GroupUserPermissions.Paused;
}
public static void SetDisableVFX(this ref GroupUserPermissions perm, bool set)
{
if (set) perm |= GroupUserPermissions.DisableVFX;
else perm &= ~GroupUserPermissions.DisableVFX;
}
}

View File

@@ -0,0 +1,61 @@
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.API.Data.Extensions;
public static class UserPermissionsExtensions
{
public static bool IsPaired(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.Paired);
}
public static bool IsPaused(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.Paused);
}
public static bool IsDisableAnimations(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.DisableAnimations);
}
public static bool IsDisableSounds(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.DisableSounds);
}
public static bool IsDisableVFX(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.DisableVFX);
}
public static void SetPaired(this ref UserPermissions perm, bool paired)
{
if (paired) perm |= UserPermissions.Paired;
else perm &= ~UserPermissions.Paired;
}
public static void SetPaused(this ref UserPermissions perm, bool paused)
{
if (paused) perm |= UserPermissions.Paused;
else perm &= ~UserPermissions.Paused;
}
public static void SetDisableAnimations(this ref UserPermissions perm, bool set)
{
if (set) perm |= UserPermissions.DisableAnimations;
else perm &= ~UserPermissions.DisableAnimations;
}
public static void SetDisableSounds(this ref UserPermissions perm, bool set)
{
if (set) perm |= UserPermissions.DisableSounds;
else perm &= ~UserPermissions.DisableSounds;
}
public static void SetDisableVFX(this ref UserPermissions perm, bool set)
{
if (set) perm |= UserPermissions.DisableVFX;
else perm &= ~UserPermissions.DisableVFX;
}
}

View File

@@ -0,0 +1,30 @@
using MessagePack;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Text;
using System.Security.Cryptography;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public class FileReplacementData
{
public FileReplacementData()
{
DataHash = new(() =>
{
var json = JsonSerializer.Serialize(this);
#pragma warning disable SYSLIB0021 // Type or member is obsolete
using SHA256CryptoServiceProvider cryptoProvider = new();
#pragma warning restore SYSLIB0021 // Type or member is obsolete
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(json))).Replace("-", "", StringComparison.Ordinal);
});
}
[JsonIgnore]
public Lazy<string> DataHash { get; }
public string[] GamePaths { get; set; } = Array.Empty<string>();
public string Hash { get; set; } = string.Empty;
public string FileSwapPath { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,10 @@
using MessagePack;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupData(string GID, string? Alias = null)
{
[IgnoreMember]
public string AliasOrGID => string.IsNullOrWhiteSpace(Alias) ? GID : Alias;
}

View File

@@ -0,0 +1,14 @@
using MessagePack;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public record SignedChatMessage(ChatMessage Message, UserData Sender) : ChatMessage(Message)
{
// Sender and timestamp are set by the server
public UserData Sender { get; set; } = Sender;
public long Timestamp { get; set; } = 0;
// Signature is generated by the server as SHA256(Sender.UID | Timestamp | Destination | Message)
// Where Destination is either the receiver's UID, or the group GID
public string Signature { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,10 @@
using MessagePack;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public record UserData(string UID, string? Alias = null)
{
[IgnoreMember]
public string AliasOrUID => string.IsNullOrWhiteSpace(Alias) ? UID : Alias;
}

View File

@@ -0,0 +1,12 @@
using MessagePack;
namespace MareSynchronos.API.Dto.Account;
[MessagePackObject(keyAsPropertyName: true)]
public record RegisterReplyDto
{
public bool Success { get; set; } = false;
public string ErrorMessage { get; set; } = string.Empty;
public string UID { get; set; } = string.Empty;
public string SecretKey { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,11 @@
using MessagePack;
namespace MareSynchronos.API.Dto.Account;
[MessagePackObject(keyAsPropertyName: true)]
public record RegisterReplyV2Dto
{
public bool Success { get; set; } = false;
public string ErrorMessage { get; set; } = string.Empty;
public string UID { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,11 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto;
[MessagePackObject(keyAsPropertyName: true)]
public record AuthReplyDto
{
public string Token { get; set; } = string.Empty;
public string? WellKnown { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace MareSynchronos.API.Dto.CharaData;
public enum AccessTypeDto
{
Individuals,
ClosePairs,
AllPairs,
Public
}

View File

@@ -0,0 +1,14 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.CharaData;
[MessagePackObject(keyAsPropertyName: true)]
public record CharaDataDownloadDto(string Id, UserData Uploader) : CharaDataDto(Id, Uploader)
{
public string GlamourerData { get; init; } = string.Empty;
public string CustomizeData { get; init; } = string.Empty;
public string ManipulationData { get; set; } = string.Empty;
public List<GamePathEntry> FileGamePaths { get; init; } = [];
public List<GamePathEntry> FileSwaps { get; init; } = [];
}

View File

@@ -0,0 +1,9 @@
using MareSynchronos.API.Data;
namespace MareSynchronos.API.Dto.CharaData;
public record CharaDataDto(string Id, UserData Uploader)
{
public string Description { get; init; } = string.Empty;
public DateTime UpdatedDate { get; init; }
}

View File

@@ -0,0 +1,88 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.CharaData;
[MessagePackObject(keyAsPropertyName: true)]
public record CharaDataFullDto(string Id, UserData Uploader) : CharaDataDto(Id, Uploader)
{
public DateTime CreatedDate { get; init; }
public DateTime ExpiryDate { get; set; }
public string GlamourerData { get; set; } = string.Empty;
public string CustomizeData { get; set; } = string.Empty;
public string ManipulationData { get; set; } = string.Empty;
public int DownloadCount { get; set; } = 0;
public List<UserData> AllowedUsers { get; set; } = [];
public List<GroupData> AllowedGroups { get; set; } = [];
public List<GamePathEntry> FileGamePaths { get; set; } = [];
public List<GamePathEntry> FileSwaps { get; set; } = [];
public List<GamePathEntry> OriginalFiles { get; set; } = [];
public AccessTypeDto AccessType { get; set; }
public ShareTypeDto ShareType { get; set; }
public List<PoseEntry> PoseData { get; set; } = [];
}
[MessagePackObject(keyAsPropertyName: true)]
public record GamePathEntry(string HashOrFileSwap, string GamePath);
[MessagePackObject(keyAsPropertyName: true)]
public record PoseEntry(long? Id)
{
public string? Description { get; set; } = string.Empty;
public string? PoseData { get; set; } = string.Empty;
public WorldData? WorldData { get; set; }
}
[MessagePackObject]
public record struct WorldData
{
[Key(0)] public LocationInfo LocationInfo { get; set; }
[Key(1)] public float PositionX { get; set; }
[Key(2)] public float PositionY { get; set; }
[Key(3)] public float PositionZ { get; set; }
[Key(4)] public float RotationX { get; set; }
[Key(5)] public float RotationY { get; set; }
[Key(6)] public float RotationZ { get; set; }
[Key(7)] public float RotationW { get; set; }
[Key(8)] public float ScaleX { get; set; }
[Key(9)] public float ScaleY { get; set; }
[Key(10)] public float ScaleZ { get; set; }
}
[MessagePackObject]
public record struct LocationInfo
{
[Key(0)] public uint ServerId { get; set; }
[Key(1)] public uint MapId { get; set; }
[Key(2)] public uint TerritoryId { get; set; }
[Key(3)] public uint DivisionId { get; set; }
[Key(4)] public uint WardId { get; set; }
[Key(5)] public uint HouseId { get; set; }
[Key(6)] public uint RoomId { get; set; }
}
[MessagePackObject]
public record struct PoseData
{
[Key(0)] public bool IsDelta { get; set; }
[Key(1)] public Dictionary<string, BoneData> Bones { get; set; }
[Key(2)] public Dictionary<string, BoneData> MainHand { get; set; }
[Key(3)] public Dictionary<string, BoneData> OffHand { get; set; }
[Key(4)] public BoneData ModelDifference { get; set; }
}
[MessagePackObject]
public record struct BoneData
{
[Key(0)] public bool Exists { get; set; }
[Key(1)] public float PositionX { get; set; }
[Key(2)] public float PositionY { get; set; }
[Key(3)] public float PositionZ { get; set; }
[Key(4)] public float RotationX { get; set; }
[Key(5)] public float RotationY { get; set; }
[Key(6)] public float RotationZ { get; set; }
[Key(7)] public float RotationW { get; set; }
[Key(8)] public float ScaleX { get; set; }
[Key(9)] public float ScaleY { get; set; }
[Key(10)] public float ScaleZ { get; set; }
}

View File

@@ -0,0 +1,11 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.CharaData;
[MessagePackObject(keyAsPropertyName: true)]
public record CharaDataMetaInfoDto(string Id, UserData Uploader) : CharaDataDto(Id, Uploader)
{
public bool CanBeDownloaded { get; init; }
public List<PoseEntry> PoseData { get; set; } = [];
}

View File

@@ -0,0 +1,20 @@
using MessagePack;
namespace MareSynchronos.API.Dto.CharaData;
[MessagePackObject(keyAsPropertyName: true)]
public record CharaDataUpdateDto(string Id)
{
public string? Description { get; set; }
public DateTime? ExpiryDate { get; set; }
public string? GlamourerData { get; set; }
public string? CustomizeData { get; set; }
public string? ManipulationData { get; set; }
public List<string>? AllowedUsers { get; set; }
public List<string>? AllowedGroups { get; set; }
public List<GamePathEntry>? FileGamePaths { get; set; }
public List<GamePathEntry>? FileSwaps { get; set; }
public AccessTypeDto? AccessType { get; set; }
public ShareTypeDto? ShareType { get; set; }
public List<PoseEntry>? Poses { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace MareSynchronos.API.Dto.CharaData;
public enum ShareTypeDto
{
Private,
Shared
}

View File

@@ -0,0 +1,13 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Dto.Group;
using MareSynchronos.API.Dto.User;
using MessagePack;
namespace MareSynchronos.API.Dto.Chat;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupChatMsgDto(GroupDto Group, SignedChatMessage Message)
{
public GroupDto Group = Group;
public SignedChatMessage Message = Message;
}

View File

@@ -0,0 +1,11 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Dto.User;
using MessagePack;
namespace MareSynchronos.API.Dto.Chat;
[MessagePackObject(keyAsPropertyName: true)]
public record UserChatMsgDto(SignedChatMessage Message)
{
public SignedChatMessage Message = Message;
}

View File

@@ -0,0 +1,25 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto;
[MessagePackObject(keyAsPropertyName: true)]
public record ConnectionDto(UserData User)
{
public Version CurrentClientVersion { get; set; } = new(0, 0, 0);
public int ServerVersion { get; set; }
public bool IsAdmin { get; set; }
public bool IsModerator { get; set; }
public ServerInfo ServerInfo { get; set; } = new();
}
[MessagePackObject(keyAsPropertyName: true)]
public record ServerInfo
{
public string ShardName { get; set; } = string.Empty;
public int MaxGroupUserCount { get; set; }
public int MaxGroupsCreatedByUser { get; set; }
public int MaxGroupsJoinedByUser { get; set; }
public Uri FileServerAddress { get; set; } = new Uri("http://nonemptyuri");
public int MaxCharaData { get; set; }
}

View File

@@ -0,0 +1,14 @@
using MessagePack;
namespace MareSynchronos.API.Dto.Files;
[MessagePackObject(keyAsPropertyName: true)]
public record DownloadFileDto : ITransferFileDto
{
public bool FileExists { get; set; } = true;
public string Hash { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public long Size { get; set; } = 0;
public bool IsForbidden { get; set; } = false;
public string ForbiddenBy { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MareSynchronos.API.Dto.Files;
public class FilesSendDto
{
public List<string> FileHashes { get; set; } = new();
public List<string> UIDs { get; set; } = new();
}

View File

@@ -0,0 +1,8 @@
namespace MareSynchronos.API.Dto.Files;
public interface ITransferFileDto
{
string Hash { get; set; }
bool IsForbidden { get; set; }
string ForbiddenBy { get; set; }
}

View File

@@ -0,0 +1,11 @@
using MessagePack;
namespace MareSynchronos.API.Dto.Files;
[MessagePackObject(keyAsPropertyName: true)]
public record UploadFileDto : ITransferFileDto
{
public string Hash { get; set; } = string.Empty;
public bool IsForbidden { get; set; } = false;
public string ForbiddenBy { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,19 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record BannedGroupUserDto : GroupPairDto
{
public BannedGroupUserDto(GroupData group, UserData user, string reason, DateTime bannedOn, string bannedBy) : base(group, user)
{
Reason = reason;
BannedOn = bannedOn;
BannedBy = bannedBy;
}
public string Reason { get; set; }
public DateTime BannedOn { get; set; }
public string BannedBy { get; set; }
}

View File

@@ -0,0 +1,13 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupDto(GroupData Group)
{
public GroupData Group { get; set; } = Group;
public string GID => Group.GID;
public string? GroupAlias => Group.Alias;
public string GroupAliasOrGID => Group.AliasOrGID;
}

View File

@@ -0,0 +1,12 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupFullInfoDto(GroupData Group, UserData Owner, GroupPermissions GroupPermissions, GroupUserPermissions GroupUserPermissions, GroupUserInfo GroupUserInfo) : GroupInfoDto(Group, Owner, GroupPermissions)
{
public GroupUserPermissions GroupUserPermissions { get; set; } = GroupUserPermissions;
public GroupUserInfo GroupUserInfo { get; set; } = GroupUserInfo;
}

View File

@@ -0,0 +1,16 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupInfoDto(GroupData Group, UserData Owner, GroupPermissions GroupPermissions) : GroupDto(Group)
{
public GroupPermissions GroupPermissions { get; set; } = GroupPermissions;
public UserData Owner { get; set; } = Owner;
public string OwnerUID => Owner.UID;
public string? OwnerAlias => Owner.Alias;
public string OwnerAliasOrUID => Owner.AliasOrUID;
}

View File

@@ -0,0 +1,12 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPairDto(GroupData Group, UserData User) : GroupDto(Group)
{
public string UID => User.UID;
public string? UserAlias => User.Alias;
public string UserAliasOrUID => User.AliasOrUID;
}

View File

@@ -0,0 +1,12 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPairFullInfoDto(GroupData Group, UserData User, GroupUserInfo GroupPairStatusInfo, GroupUserPermissions GroupUserPermissions) : GroupPairDto(Group, User)
{
public GroupUserInfo GroupPairStatusInfo { get; set; } = GroupPairStatusInfo;
public GroupUserPermissions GroupUserPermissions { get; set; } = GroupUserPermissions;
}

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPairUserInfoDto(GroupData Group, UserData User, GroupUserInfo GroupUserInfo) : GroupPairDto(Group, User);

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPairUserPermissionDto(GroupData Group, UserData User, GroupUserPermissions GroupPairPermissions) : GroupPairDto(Group, User);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPasswordDto(GroupData Group, string Password) : GroupDto(Group);

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPermissionDto(GroupData Group, GroupPermissions Permissions) : GroupDto(Group);

View File

@@ -0,0 +1,9 @@
using MessagePack;
namespace MareSynchronos.API.Dto;
[MessagePackObject(keyAsPropertyName: true)]
public record SystemInfoDto
{
public int OnlineUsers { get; set; }
}

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record OnlineUserCharaDataDto(UserData User, CharacterData CharaData) : UserDto(User);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record OnlineUserIdentDto(UserData User, string Ident) : UserDto(User);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserCharaDataMessageDto(List<UserData> Recipients, CharacterData CharaData);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserDto(UserData User);

View File

@@ -0,0 +1,12 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserPairDto(UserData User, UserPermissions OwnPermissions, UserPermissions OtherPermissions) : UserDto(User)
{
public UserPermissions OwnPermissions { get; set; } = OwnPermissions;
public UserPermissions OtherPermissions { get; set; } = OtherPermissions;
}

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserPermissionsDto(UserData User, UserPermissions Permissions) : UserDto(User);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserProfileDto(UserData User, bool Disabled, bool? IsNSFW, string? ProfilePictureBase64, string? Description) : UserDto(User);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserProfileReportDto(UserData User, string ProfileReport) : UserDto(User);

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MessagePack.Annotations" Version="2.5.129" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32602.215
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronos.API", "MareSynchronos.API.csproj", "{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DFB70C71-AB27-468D-A08B-218CA79BF69D}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,14 @@
namespace MareSynchronos.API.Routes;
public class MareAuth
{
public const string Auth = "/auth";
public const string Auth_CreateIdent = "createWithIdent";
public const string Auth_CreateIdentV2 = "createWithIdentV2";
public const string Auth_Register = "registerNewKey";
public const string Auth_RegisterV2 = "registerNewKeyV2";
public static Uri AuthFullPath(Uri baseUri) => new Uri(baseUri, Auth + "/" + Auth_CreateIdent);
public static Uri AuthV2FullPath(Uri baseUri) => new Uri(baseUri, Auth + "/" + Auth_CreateIdentV2);
public static Uri AuthRegisterFullPath(Uri baseUri) => new Uri(baseUri, Auth + "/" + Auth_Register);
public static Uri AuthRegisterV2FullPath(Uri baseUri) => new Uri(baseUri, Auth + "/" + Auth_RegisterV2);
}

View File

@@ -0,0 +1,45 @@
namespace MareSynchronos.API.Routes;
public class MareFiles
{
public const string Cache = "/cache";
public const string Cache_Get = "get";
public const string Request = "/request";
public const string Request_Cancel = "cancel";
public const string Request_Check = "check";
public const string Request_Enqueue = "enqueue";
public const string Request_RequestFile = "file";
public const string ServerFiles = "/files";
public const string ServerFiles_DeleteAll = "deleteAll";
public const string ServerFiles_FilesSend = "filesSend";
public const string ServerFiles_GetSizes = "getFileSizes";
public const string ServerFiles_Upload = "upload";
public const string ServerFiles_UploadRaw = "uploadRaw";
public const string ServerFiles_UploadMunged = "uploadMunged";
public const string Distribution = "/dist";
public const string Distribution_Get = "get";
public const string Main = "/main";
public const string Main_SendReady = "sendReady";
public static Uri CacheGetFullPath(Uri baseUri, Guid requestId) => new(baseUri, Cache + "/" + Cache_Get + "?requestId=" + requestId.ToString());
public static Uri RequestCancelFullPath(Uri baseUri, Guid guid) => new Uri(baseUri, Request + "/" + Request_Cancel + "?requestId=" + guid.ToString());
public static Uri RequestCheckQueueFullPath(Uri baseUri, Guid guid) => new Uri(baseUri, Request + "/" + Request_Check + "?requestId=" + guid.ToString());
public static Uri RequestEnqueueFullPath(Uri baseUri) => new(baseUri, Request + "/" + Request_Enqueue);
public static Uri RequestRequestFileFullPath(Uri baseUri, string hash) => new(baseUri, Request + "/" + Request_RequestFile + "?file=" + hash);
public static Uri ServerFilesDeleteAllFullPath(Uri baseUri) => new(baseUri, ServerFiles + "/" + ServerFiles_DeleteAll);
public static Uri ServerFilesFilesSendFullPath(Uri baseUri) => new(baseUri, ServerFiles + "/" + ServerFiles_FilesSend);
public static Uri ServerFilesGetSizesFullPath(Uri baseUri) => new(baseUri, ServerFiles + "/" + ServerFiles_GetSizes);
public static Uri ServerFilesUploadFullPath(Uri baseUri, string hash) => new(baseUri, ServerFiles + "/" + ServerFiles_Upload + "/" + hash);
public static Uri ServerFilesUploadRawFullPath(Uri baseUri, string hash) => new(baseUri, ServerFiles + "/" + ServerFiles_UploadRaw + "/" + hash);
public static Uri ServerFilesUploadMunged(Uri baseUri, string hash) => new(baseUri, ServerFiles + "/" + ServerFiles_UploadMunged + "/" + hash);
public static Uri DistributionGetFullPath(Uri baseUri, string hash) => new(baseUri, Distribution + "/" + Distribution_Get + "?file=" + hash);
public static Uri MainSendReadyFullPath(Uri baseUri, string uid, Guid request) => new(baseUri, Main + "/" + Main_SendReady + "/" + "?uid=" + uid + "&requestId=" + request.ToString());
}

View File

@@ -0,0 +1,144 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MareSynchronos.API.Dto;
using MareSynchronos.API.Dto.CharaData;
using MareSynchronos.API.Dto.Chat;
using MareSynchronos.API.Dto.Group;
using MareSynchronos.API.Dto.User;
namespace MareSynchronos.API.SignalR;
public interface IMareHub
{
const int ApiVersion = 1026;
const string Path = "/mare";
Task<bool> CheckClientHealth();
Task Client_DownloadReady(Guid requestId);
Task Client_GroupChangePermissions(GroupPermissionDto groupPermission);
Task Client_GroupChatMsg(GroupChatMsgDto groupChatMsgDto);
Task Client_GroupDelete(GroupDto groupDto);
Task Client_GroupPairChangePermissions(GroupPairUserPermissionDto permissionDto);
Task Client_GroupPairChangeUserInfo(GroupPairUserInfoDto userInfo);
Task Client_GroupPairJoined(GroupPairFullInfoDto groupPairInfoDto);
Task Client_GroupPairLeft(GroupPairDto groupPairDto);
Task Client_GroupSendFullInfo(GroupFullInfoDto groupInfo);
Task Client_GroupSendInfo(GroupInfoDto groupInfo);
Task Client_ReceiveServerMessage(MessageSeverity messageSeverity, string message);
Task Client_UpdateSystemInfo(SystemInfoDto systemInfo);
Task Client_UserAddClientPair(UserPairDto dto);
Task Client_UserChatMsg(UserChatMsgDto chatMsgDto);
Task Client_UserReceiveCharacterData(OnlineUserCharaDataDto dataDto);
Task Client_UserReceiveUploadStatus(UserDto dto);
Task Client_UserRemoveClientPair(UserDto dto);
Task Client_UserSendOffline(UserDto dto);
Task Client_UserSendOnline(OnlineUserIdentDto dto);
Task Client_UserUpdateOtherPairPermissions(UserPermissionsDto dto);
Task Client_UserUpdateProfile(UserDto dto);
Task Client_UserUpdateSelfPairPermissions(UserPermissionsDto dto);
Task Client_GposeLobbyJoin(UserData userData);
Task Client_GposeLobbyLeave(UserData userData);
Task Client_GposeLobbyPushCharacterData(CharaDataDownloadDto charaDownloadDto);
Task Client_GposeLobbyPushPoseData(UserData userData, PoseData poseData);
Task Client_GposeLobbyPushWorldData(UserData userData, WorldData worldData);
Task<ConnectionDto> GetConnectionDto();
Task GroupBanUser(GroupPairDto dto, string reason);
Task GroupChangeGroupPermissionState(GroupPermissionDto dto);
Task GroupChangeIndividualPermissionState(GroupPairUserPermissionDto dto);
Task GroupChangeOwnership(GroupPairDto groupPair);
Task<bool> GroupChangePassword(GroupPasswordDto groupPassword);
Task GroupChatSendMsg(GroupDto group, ChatMessage message);
Task GroupClear(GroupDto group);
Task<GroupPasswordDto> GroupCreate();
Task<List<string>> GroupCreateTempInvite(GroupDto group, int amount);
Task GroupDelete(GroupDto group);
Task<List<BannedGroupUserDto>> GroupGetBannedUsers(GroupDto group);
Task<bool> GroupJoin(GroupPasswordDto passwordedGroup);
Task GroupLeave(GroupDto group);
Task GroupRemoveUser(GroupPairDto groupPair);
Task GroupSetUserInfo(GroupPairUserInfoDto groupPair);
Task<List<GroupFullInfoDto>> GroupsGetAll();
Task<List<GroupPairFullInfoDto>> GroupsGetUsersInGroup(GroupDto group);
Task GroupUnbanUser(GroupPairDto groupPair);
Task<int> GroupPrune(GroupDto group, int days, bool execute);
Task UserAddPair(UserDto user);
Task UserChatSendMsg(UserDto user, ChatMessage message);
Task UserDelete();
Task<List<OnlineUserIdentDto>> UserGetOnlinePairs();
Task<List<UserPairDto>> UserGetPairedClients();
Task<UserProfileDto> UserGetProfile(UserDto dto);
Task UserPushData(UserCharaDataMessageDto dto);
Task UserRemovePair(UserDto userDto);
Task UserReportProfile(UserProfileReportDto userDto);
Task UserSetPairPermissions(UserPermissionsDto userPermissions);
Task UserSetProfile(UserProfileDto userDescription);
Task<CharaDataFullDto?> CharaDataCreate();
Task<CharaDataFullDto?> CharaDataUpdate(CharaDataUpdateDto updateDto);
Task<bool> CharaDataDelete(string id);
Task<CharaDataMetaInfoDto?> CharaDataGetMetainfo(string id);
Task<CharaDataDownloadDto?> CharaDataDownload(string id);
Task<List<CharaDataFullDto>> CharaDataGetOwn();
Task<List<CharaDataMetaInfoDto>> CharaDataGetShared();
Task<CharaDataFullDto?> CharaDataAttemptRestore(string id);
Task<string> GposeLobbyCreate();
Task<List<UserData>> GposeLobbyJoin(string lobbyId);
Task<bool> GposeLobbyLeave();
Task GposeLobbyPushCharacterData(CharaDataDownloadDto charaDownloadDto);
Task GposeLobbyPushPoseData(PoseData poseData);
Task GposeLobbyPushWorldData(WorldData worldData);
}

View File

@@ -0,0 +1,62 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MareSynchronos.API.Dto;
using MareSynchronos.API.Dto.CharaData;
using MareSynchronos.API.Dto.Chat;
using MareSynchronos.API.Dto.Group;
using MareSynchronos.API.Dto.User;
namespace MareSynchronos.API.SignalR;
public interface IMareHubClient : IMareHub
{
void OnDownloadReady(Action<Guid> act);
void OnGroupChangePermissions(Action<GroupPermissionDto> act);
void OnGroupChatMsg(Action<GroupChatMsgDto> groupChatMsgDto);
void OnGroupDelete(Action<GroupDto> act);
void OnGroupPairChangePermissions(Action<GroupPairUserPermissionDto> act);
void OnGroupPairChangeUserInfo(Action<GroupPairUserInfoDto> act);
void OnGroupPairJoined(Action<GroupPairFullInfoDto> act);
void OnGroupPairLeft(Action<GroupPairDto> act);
void OnGroupSendFullInfo(Action<GroupFullInfoDto> act);
void OnGroupSendInfo(Action<GroupInfoDto> act);
void OnReceiveServerMessage(Action<MessageSeverity, string> act);
void OnUpdateSystemInfo(Action<SystemInfoDto> act);
void OnUserAddClientPair(Action<UserPairDto> act);
void OnUserChatMsg(Action<UserChatMsgDto> chatMsgDto);
void OnUserReceiveCharacterData(Action<OnlineUserCharaDataDto> act);
void OnUserReceiveUploadStatus(Action<UserDto> act);
void OnUserRemoveClientPair(Action<UserDto> act);
void OnUserSendOffline(Action<UserDto> act);
void OnUserSendOnline(Action<OnlineUserIdentDto> act);
void OnUserUpdateOtherPairPermissions(Action<UserPermissionsDto> act);
void OnUserUpdateProfile(Action<UserDto> act);
void OnUserUpdateSelfPairPermissions(Action<UserPermissionsDto> act);
void OnGposeLobbyJoin(Action<UserData> act);
void OnGposeLobbyLeave(Action<UserData> act);
void OnGposeLobbyPushCharacterData(Action<CharaDataDownloadDto> act);
void OnGposeLobbyPushPoseData(Action<UserData, PoseData> act);
void OnGposeLobbyPushWorldData(Action<UserData, WorldData> act);
}