Compare commits
10 Commits
73fc5bea2c
...
8cc2dd2330
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cc2dd2330 | ||
|
|
ee125aaa85 | ||
|
|
5c7d5ff29a | ||
|
|
0b1e08181d | ||
|
|
17d10e2b65 | ||
|
|
fe0835adf8 | ||
|
|
bb03885e2d | ||
|
|
4b0c5f6199 | ||
|
|
c12559afcc | ||
|
|
82a40d543a |
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
|||||||
[submodule "MareAPI"]
|
[submodule "MareAPI"]
|
||||||
path = MareAPI
|
path = MareAPI
|
||||||
url = https://github.com/loporrit/MareAPI.git
|
url = https://git.lop-sync.com/huggingway/LopAPI.git
|
||||||
|
|||||||
2
MareAPI
2
MareAPI
Submodule MareAPI updated: 4d8c380dab...b2f4453b79
@@ -1,4 +1,6 @@
|
|||||||
using MareSynchronos.API.Routes;
|
using MareSynchronos.API.Dto;
|
||||||
|
using MareSynchronos.API.Dto.Account;
|
||||||
|
using MareSynchronos.API.Routes;
|
||||||
using MareSynchronosAuthService.Services;
|
using MareSynchronosAuthService.Services;
|
||||||
using MareSynchronosShared;
|
using MareSynchronosShared;
|
||||||
using MareSynchronosShared.Data;
|
using MareSynchronosShared.Data;
|
||||||
@@ -124,13 +126,54 @@ public class JwtController : Controller
|
|||||||
return Content(token.RawData);
|
return Content(token.RawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpPost(MareAuth.Auth_CreateIdentV2)]
|
||||||
|
public async Task<IActionResult> CreateTokenV2(string auth, string charaIdent)
|
||||||
|
{
|
||||||
|
var tokenResponse = await CreateToken(auth, charaIdent);
|
||||||
|
var tokenContent = tokenResponse as ContentResult;
|
||||||
|
if (tokenContent == null)
|
||||||
|
return tokenResponse;
|
||||||
|
return Json(new AuthReplyDto
|
||||||
|
{
|
||||||
|
Token = tokenContent.Content,
|
||||||
|
WellKnown = _configuration.GetValueOrDefault(nameof(AuthServiceConfiguration.WellKnown), string.Empty),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[HttpPost(MareAuth.Auth_Register)]
|
[HttpPost(MareAuth.Auth_Register)]
|
||||||
public async Task<IActionResult> Register()
|
public async Task<IActionResult> Register()
|
||||||
{
|
{
|
||||||
var ua = HttpContext.Request.Headers["User-Agent"][0] ?? "-";
|
var ua = HttpContext.Request.Headers["User-Agent"][0] ?? "-";
|
||||||
var ip = _accessor.GetIpAddress();
|
var ip = _accessor.GetIpAddress();
|
||||||
return Json(await _accountRegistrationService.RegisterAccountAsync(ua, ip));
|
|
||||||
|
// Legacy endpoint: generate a secret key for the user
|
||||||
|
var computedHash = StringUtils.Sha256String(StringUtils.GenerateRandomString(64) + DateTime.UtcNow.ToString());
|
||||||
|
var hashedKey = StringUtils.Sha256String(computedHash);
|
||||||
|
|
||||||
|
var dto = await _accountRegistrationService.RegisterAccountAsync(ua, ip, hashedKey);
|
||||||
|
|
||||||
|
return Json(new RegisterReplyDto()
|
||||||
|
{
|
||||||
|
Success = dto.Success,
|
||||||
|
ErrorMessage = dto.ErrorMessage,
|
||||||
|
UID = dto.UID,
|
||||||
|
SecretKey = computedHash
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpPost(MareAuth.Auth_RegisterV2)]
|
||||||
|
public async Task<IActionResult> RegisterV2(string hashedSecretKey)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(hashedSecretKey)) return BadRequest("No HashedSecretKey");
|
||||||
|
if (hashedSecretKey.Length != 64) return BadRequest("Bad HashedSecretKey");
|
||||||
|
if (!hashedSecretKey.All(char.IsAsciiHexDigitUpper)) return BadRequest("Bad HashedSecretKey");
|
||||||
|
|
||||||
|
var ua = HttpContext.Request.Headers["User-Agent"][0] ?? "-";
|
||||||
|
var ip = _accessor.GetIpAddress();
|
||||||
|
return Json(await _accountRegistrationService.RegisterAccountAsync(ua, ip, hashedSecretKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
private JwtSecurityToken CreateToken(IEnumerable<Claim> authClaims)
|
private JwtSecurityToken CreateToken(IEnumerable<Claim> authClaims)
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ public class AccountRegistrationService
|
|||||||
_serviceScopeFactory = serviceScopeFactory;
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<RegisterReplyDto> RegisterAccountAsync(string ua, string ip)
|
public async Task<RegisterReplyV2Dto> RegisterAccountAsync(string ua, string ip, string hashedSecretKey)
|
||||||
{
|
{
|
||||||
var reply = new RegisterReplyDto();
|
var reply = new RegisterReplyV2Dto();
|
||||||
|
|
||||||
if (!_registrationUserAgentRegex.Match(ua).Success)
|
if (!_registrationUserAgentRegex.Match(ua).Success)
|
||||||
{
|
{
|
||||||
@@ -99,10 +99,9 @@ public class AccountRegistrationService
|
|||||||
|
|
||||||
user.LastLoggedIn = DateTime.UtcNow;
|
user.LastLoggedIn = DateTime.UtcNow;
|
||||||
|
|
||||||
var computedHash = StringUtils.Sha256String(StringUtils.GenerateRandomString(64) + DateTime.UtcNow.ToString());
|
|
||||||
var auth = new Auth()
|
var auth = new Auth()
|
||||||
{
|
{
|
||||||
HashedKey = StringUtils.Sha256String(computedHash),
|
HashedKey = hashedSecretKey,
|
||||||
User = user,
|
User = user,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,7 +114,6 @@ public class AccountRegistrationService
|
|||||||
|
|
||||||
reply.Success = true;
|
reply.Success = true;
|
||||||
reply.UID = user.UID;
|
reply.UID = user.UID;
|
||||||
reply.SecretKey = computedHash;
|
|
||||||
|
|
||||||
RecordIpRegistration(ip);
|
RecordIpRegistration(ip);
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,55 @@ public partial class MareHub
|
|||||||
return [.. ownCharaData.Select(GetCharaDataFullDto)];
|
return [.. ownCharaData.Select(GetCharaDataFullDto)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<CharaDataFullDto?> CharaDataAttemptRestore(string id)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(id));
|
||||||
|
var charaData = await DbContext.CharaData
|
||||||
|
.Include(u => u.Files)
|
||||||
|
.Include(u => u.FileSwaps)
|
||||||
|
.Include(u => u.OriginalFiles)
|
||||||
|
.Include(u => u.AllowedIndividiuals)
|
||||||
|
.ThenInclude(u => u.AllowedUser)
|
||||||
|
.Include(u => u.AllowedIndividiuals)
|
||||||
|
.ThenInclude(u => u.AllowedGroup)
|
||||||
|
.Include(u => u.Poses)
|
||||||
|
.AsSplitQuery()
|
||||||
|
.SingleOrDefaultAsync(s => s.Id == id && s.UploaderUID == UserUID)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
if (charaData == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var currentHashes = charaData.Files.Select(f => f.FileCacheHash).ToList();
|
||||||
|
var missingFiles = charaData.OriginalFiles.Where(c => !currentHashes.Contains(c.Hash, StringComparer.Ordinal)).ToList();
|
||||||
|
|
||||||
|
// now let's see what's on the db still
|
||||||
|
var existingDbFiles = await DbContext.Files
|
||||||
|
.Where(f => missingFiles.Select(k => k.Hash).Distinct().Contains(f.Hash))
|
||||||
|
.ToListAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
// now shove it all back into the db
|
||||||
|
foreach (var dbFile in existingDbFiles)
|
||||||
|
{
|
||||||
|
var missingFileEntry = missingFiles.First(f => string.Equals(f.Hash, dbFile.Hash, StringComparison.Ordinal));
|
||||||
|
charaData.Files.Add(new CharaDataFile()
|
||||||
|
{
|
||||||
|
FileCache = dbFile,
|
||||||
|
GamePath = missingFileEntry.GamePath,
|
||||||
|
Parent = charaData
|
||||||
|
});
|
||||||
|
missingFiles.Remove(missingFileEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingDbFiles.Any())
|
||||||
|
{
|
||||||
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetCharaDataFullDto(charaData);
|
||||||
|
}
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
[Authorize(Policy = "Identified")]
|
||||||
public async Task<List<CharaDataMetaInfoDto>> CharaDataGetShared()
|
public async Task<List<CharaDataMetaInfoDto>> CharaDataGetShared()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using MareSynchronos.API.Data.Enum;
|
using MareSynchronos.API.Data;
|
||||||
|
using MareSynchronos.API.Data.Enum;
|
||||||
using MareSynchronos.API.Dto;
|
using MareSynchronos.API.Dto;
|
||||||
|
using MareSynchronos.API.Dto.CharaData;
|
||||||
using MareSynchronos.API.Dto.Chat;
|
using MareSynchronos.API.Dto.Chat;
|
||||||
using MareSynchronos.API.Dto.Group;
|
using MareSynchronos.API.Dto.Group;
|
||||||
using MareSynchronos.API.Dto.User;
|
using MareSynchronos.API.Dto.User;
|
||||||
@@ -51,5 +53,11 @@ namespace MareSynchronosServer.Hubs
|
|||||||
public Task Client_UserUpdateProfile(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
public Task Client_UserUpdateProfile(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
||||||
|
|
||||||
public Task Client_UserUpdateSelfPairPermissions(UserPermissionsDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
public Task Client_UserUpdateSelfPairPermissions(UserPermissionsDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
||||||
|
|
||||||
|
public Task Client_GposeLobbyJoin(UserData userData) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
||||||
|
public Task Client_GposeLobbyLeave(UserData userData) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
||||||
|
public Task Client_GposeLobbyPushCharacterData(CharaDataDownloadDto charaDownloadDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
||||||
|
public Task Client_GposeLobbyPushPoseData(UserData userData, PoseData poseData) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
||||||
|
public Task Client_GposeLobbyPushWorldData(UserData userData, WorldData worldData) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
using MareSynchronos.API.Data;
|
||||||
|
using MareSynchronos.API.Dto.CharaData;
|
||||||
|
using MareSynchronosServer.Utils;
|
||||||
|
using MareSynchronosShared.Metrics;
|
||||||
|
using MareSynchronosShared.Utils;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace MareSynchronosServer.Hubs;
|
||||||
|
|
||||||
|
public partial class MareHub
|
||||||
|
{
|
||||||
|
private async Task<string?> GetUserGposeLobby()
|
||||||
|
{
|
||||||
|
return await _redis.GetAsync<string>(GposeLobbyUser).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<string>> GetUsersInLobby(string lobbyId, bool includeSelf = false)
|
||||||
|
{
|
||||||
|
var users = await _redis.GetAsync<List<string>>($"GposeLobby:{lobbyId}").ConfigureAwait(false);
|
||||||
|
return users?.Where(u => includeSelf || !string.Equals(u, UserUID, StringComparison.Ordinal)).ToList() ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddUserToLobby(string lobbyId, List<string> priorUsers)
|
||||||
|
{
|
||||||
|
_mareMetrics.IncGauge(MetricsAPI.GaugeGposeLobbyUsers);
|
||||||
|
if (priorUsers.Count == 0)
|
||||||
|
_mareMetrics.IncGauge(MetricsAPI.GaugeGposeLobbies);
|
||||||
|
|
||||||
|
await _redis.AddAsync(GposeLobbyUser, lobbyId).ConfigureAwait(false);
|
||||||
|
await _redis.AddAsync($"GposeLobby:{lobbyId}", priorUsers.Concat([UserUID])).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RemoveUserFromLobby(string lobbyId, List<string> priorUsers)
|
||||||
|
{
|
||||||
|
await _redis.RemoveAsync(GposeLobbyUser).ConfigureAwait(false);
|
||||||
|
|
||||||
|
_mareMetrics.DecGauge(MetricsAPI.GaugeGposeLobbyUsers);
|
||||||
|
|
||||||
|
if (priorUsers.Count == 1)
|
||||||
|
{
|
||||||
|
await _redis.RemoveAsync($"GposeLobby:{lobbyId}").ConfigureAwait(false);
|
||||||
|
_mareMetrics.DecGauge(MetricsAPI.GaugeGposeLobbies);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
priorUsers.Remove(UserUID);
|
||||||
|
await _redis.AddAsync($"GposeLobby:{lobbyId}", priorUsers).ConfigureAwait(false);
|
||||||
|
await Clients.Users(priorUsers).Client_GposeLobbyLeave(new(UserUID)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GposeLobbyUser => $"GposeLobbyUser:{UserUID}";
|
||||||
|
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<string> GposeLobbyCreate()
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
var alreadyInLobby = await GetUserGposeLobby().ConfigureAwait(false);
|
||||||
|
if (!string.IsNullOrEmpty(alreadyInLobby))
|
||||||
|
{
|
||||||
|
throw new HubException("Already in GPose Lobby, cannot join another");
|
||||||
|
}
|
||||||
|
|
||||||
|
string lobbyId = string.Empty;
|
||||||
|
while (string.IsNullOrEmpty(lobbyId))
|
||||||
|
{
|
||||||
|
lobbyId = StringUtils.GenerateRandomString(30, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
||||||
|
var result = await _redis.GetAsync<List<string>>($"GposeLobby:{lobbyId}").ConfigureAwait(false);
|
||||||
|
if (result != null)
|
||||||
|
lobbyId = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
await AddUserToLobby(lobbyId, []).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return lobbyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<List<UserData>> GposeLobbyJoin(string lobbyId)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
var existingLobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
||||||
|
if (!string.IsNullOrEmpty(existingLobbyId))
|
||||||
|
await GposeLobbyLeave().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var lobbyUsers = await GetUsersInLobby(lobbyId).ConfigureAwait(false);
|
||||||
|
if (!lobbyUsers.Any())
|
||||||
|
return [];
|
||||||
|
|
||||||
|
await AddUserToLobby(lobbyId, lobbyUsers).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var user = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
||||||
|
await Clients.Users(lobbyUsers.Where(u => !string.Equals(u, UserUID, StringComparison.Ordinal)))
|
||||||
|
.Client_GposeLobbyJoin(user.ToUserData()).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var users = await DbContext.Users.Where(u => lobbyUsers.Contains(u.UID))
|
||||||
|
.Select(u => u.ToUserData())
|
||||||
|
.ToListAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<bool> GposeLobbyLeave()
|
||||||
|
{
|
||||||
|
var lobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
||||||
|
if (string.IsNullOrEmpty(lobbyId))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
|
var lobbyUsers = await GetUsersInLobby(lobbyId, true).ConfigureAwait(false);
|
||||||
|
await RemoveUserFromLobby(lobbyId, lobbyUsers).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task GposeLobbyPushCharacterData(CharaDataDownloadDto charaDataDownloadDto)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
var lobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
||||||
|
if (string.IsNullOrEmpty(lobbyId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var lobbyUsers = await GetUsersInLobby(lobbyId).ConfigureAwait(false);
|
||||||
|
await Clients.Users(lobbyUsers).Client_GposeLobbyPushCharacterData(charaDataDownloadDto).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task GposeLobbyPushPoseData(PoseData poseData)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
var lobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
||||||
|
if (string.IsNullOrEmpty(lobbyId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await _gPoseLobbyDistributionService.PushPoseData(lobbyId, UserUID, poseData).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task GposeLobbyPushWorldData(WorldData worldData)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
var lobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
||||||
|
if (string.IsNullOrEmpty(lobbyId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await _gPoseLobbyDistributionService.PushWorldData(lobbyId, UserUID, worldData).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,7 +135,6 @@ public partial class MareHub
|
|||||||
var prevOwner = await DbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == dto.Group.GID && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
var prevOwner = await DbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == dto.Group.GID && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||||
prevOwner.IsPinned = false;
|
prevOwner.IsPinned = false;
|
||||||
group.Owner = newOwnerPair.GroupUser;
|
group.Owner = newOwnerPair.GroupUser;
|
||||||
group.Alias = null;
|
|
||||||
newOwnerPair.IsPinned = true;
|
newOwnerPair.IsPinned = true;
|
||||||
newOwnerPair.IsModerator = false;
|
newOwnerPair.IsModerator = false;
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
|||||||
private readonly int _maxJoinedGroupsByUser;
|
private readonly int _maxJoinedGroupsByUser;
|
||||||
private readonly int _maxGroupUserCount;
|
private readonly int _maxGroupUserCount;
|
||||||
private readonly IRedisDatabase _redis;
|
private readonly IRedisDatabase _redis;
|
||||||
|
private readonly GPoseLobbyDistributionService _gPoseLobbyDistributionService;
|
||||||
private readonly Uri _fileServerAddress;
|
private readonly Uri _fileServerAddress;
|
||||||
private readonly Version _expectedClientVersion;
|
private readonly Version _expectedClientVersion;
|
||||||
private readonly int _maxCharaDataByUser;
|
private readonly int _maxCharaDataByUser;
|
||||||
@@ -38,7 +39,7 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
|||||||
public MareHub(MareMetrics mareMetrics,
|
public MareHub(MareMetrics mareMetrics,
|
||||||
IDbContextFactory<MareDbContext> mareDbContextFactory, ILogger<MareHub> logger, SystemInfoService systemInfoService,
|
IDbContextFactory<MareDbContext> mareDbContextFactory, ILogger<MareHub> logger, SystemInfoService systemInfoService,
|
||||||
IConfigurationService<ServerConfiguration> configuration, IHttpContextAccessor contextAccessor,
|
IConfigurationService<ServerConfiguration> configuration, IHttpContextAccessor contextAccessor,
|
||||||
IRedisDatabase redisDb)
|
IRedisDatabase redisDb, GPoseLobbyDistributionService gPoseLobbyDistributionService)
|
||||||
{
|
{
|
||||||
_mareMetrics = mareMetrics;
|
_mareMetrics = mareMetrics;
|
||||||
_systemInfoService = systemInfoService;
|
_systemInfoService = systemInfoService;
|
||||||
@@ -51,6 +52,7 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
|||||||
_maxCharaDataByUser = configuration.GetValueOrDefault(nameof(ServerConfiguration.MaxCharaDataByUser), 10);
|
_maxCharaDataByUser = configuration.GetValueOrDefault(nameof(ServerConfiguration.MaxCharaDataByUser), 10);
|
||||||
_contextAccessor = contextAccessor;
|
_contextAccessor = contextAccessor;
|
||||||
_redis = redisDb;
|
_redis = redisDb;
|
||||||
|
_gPoseLobbyDistributionService = gPoseLobbyDistributionService;
|
||||||
_logger = new MareHubLogger(this, logger);
|
_logger = new MareHubLogger(this, logger);
|
||||||
_dbContextLazy = new Lazy<MareDbContext>(() => mareDbContextFactory.CreateDbContext());
|
_dbContextLazy = new Lazy<MareDbContext>(() => mareDbContextFactory.CreateDbContext());
|
||||||
}
|
}
|
||||||
@@ -133,6 +135,7 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
|||||||
if (exception != null)
|
if (exception != null)
|
||||||
_logger.LogCallWarning(MareHubLogger.Args(_contextAccessor.GetIpAddress(), exception.Message, exception.StackTrace));
|
_logger.LogCallWarning(MareHubLogger.Args(_contextAccessor.GetIpAddress(), exception.Message, exception.StackTrace));
|
||||||
|
|
||||||
|
await GposeLobbyLeave().ConfigureAwait(false);
|
||||||
await RemoveUserFromRedis().ConfigureAwait(false);
|
await RemoveUserFromRedis().ConfigureAwait(false);
|
||||||
|
|
||||||
await SendOfflineToAllPairedUsers().ConfigureAwait(false);
|
await SendOfflineToAllPairedUsers().ConfigureAwait(false);
|
||||||
|
|||||||
@@ -0,0 +1,226 @@
|
|||||||
|
using MareSynchronos.API.Dto.CharaData;
|
||||||
|
using MareSynchronos.API.SignalR;
|
||||||
|
using MareSynchronosServer.Hubs;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using StackExchange.Redis.Extensions.Core.Abstractions;
|
||||||
|
|
||||||
|
namespace MareSynchronosServer.Services;
|
||||||
|
|
||||||
|
public sealed class GPoseLobbyDistributionService : IHostedService, IDisposable
|
||||||
|
{
|
||||||
|
private CancellationTokenSource _runtimeCts = new();
|
||||||
|
private readonly Dictionary<string, Dictionary<string, WorldData>> _lobbyWorldData = [];
|
||||||
|
private readonly Dictionary<string, Dictionary<string, PoseData>> _lobbyPoseData = [];
|
||||||
|
private readonly SemaphoreSlim _lobbyPoseDataModificationSemaphore = new(1, 1);
|
||||||
|
private readonly SemaphoreSlim _lobbyWorldDataModificationSemaphore = new(1, 1);
|
||||||
|
|
||||||
|
public GPoseLobbyDistributionService(ILogger<GPoseLobbyDistributionService> logger, IRedisDatabase redisDb,
|
||||||
|
IHubContext<MareHub, IMareHub> hubContext)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_redisDb = redisDb;
|
||||||
|
_hubContext = hubContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
private readonly ILogger<GPoseLobbyDistributionService> _logger;
|
||||||
|
private readonly IRedisDatabase _redisDb;
|
||||||
|
private readonly IHubContext<MareHub, IMareHub> _hubContext;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_runtimeCts.Cancel();
|
||||||
|
_runtimeCts.Dispose();
|
||||||
|
_lobbyPoseDataModificationSemaphore.Dispose();
|
||||||
|
_lobbyWorldDataModificationSemaphore.Dispose();
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PushWorldData(string lobby, string user, WorldData worldData)
|
||||||
|
{
|
||||||
|
await _lobbyWorldDataModificationSemaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_lobbyWorldData.TryGetValue(lobby, out var worldDataDict))
|
||||||
|
{
|
||||||
|
_lobbyWorldData[lobby] = worldDataDict = new(StringComparer.Ordinal);
|
||||||
|
}
|
||||||
|
worldDataDict[user] = worldData;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during Pushing World Data for Lobby {lobby} by User {user}", lobby, user);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lobbyWorldDataModificationSemaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PushPoseData(string lobby, string user, PoseData poseData)
|
||||||
|
{
|
||||||
|
await _lobbyPoseDataModificationSemaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_lobbyPoseData.TryGetValue(lobby, out var poseDataDict))
|
||||||
|
{
|
||||||
|
_lobbyPoseData[lobby] = poseDataDict = new(StringComparer.Ordinal);
|
||||||
|
}
|
||||||
|
poseDataDict[user] = poseData;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during Pushing World Data for Lobby {lobby} by User {user}", lobby, user);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lobbyPoseDataModificationSemaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_ = WorldDataDistribution(_runtimeCts.Token);
|
||||||
|
_ = PoseDataDistribution(_runtimeCts.Token);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task WorldDataDistribution(CancellationToken token)
|
||||||
|
{
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await DistributeWorldData(token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during World Data Distribution");
|
||||||
|
}
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PoseDataDistribution(CancellationToken token)
|
||||||
|
{
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await DistributePoseData(token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during Pose Data Distribution");
|
||||||
|
}
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(2), token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DistributeWorldData(CancellationToken token)
|
||||||
|
{
|
||||||
|
await _lobbyWorldDataModificationSemaphore.WaitAsync(token).ConfigureAwait(false);
|
||||||
|
Dictionary<string, Dictionary<string, WorldData>> clone = [];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
clone = _lobbyWorldData.ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal);
|
||||||
|
_lobbyWorldData.Clear();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during Distributing World Data Clone generation");
|
||||||
|
_lobbyWorldData.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lobbyWorldDataModificationSemaphore.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var lobbyId in clone)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!lobbyId.Value.Values.Any())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var gposeLobbyUsers = await _redisDb.GetAsync<List<string>>($"GposeLobby:{lobbyId.Key}").ConfigureAwait(false);
|
||||||
|
if (gposeLobbyUsers == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var data in lobbyId.Value)
|
||||||
|
{
|
||||||
|
await _hubContext.Clients.Users(gposeLobbyUsers.Where(k => !string.Equals(k, data.Key, StringComparison.Ordinal)))
|
||||||
|
.Client_GposeLobbyPushWorldData(new(data.Key), data.Value).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during World Data Distribution for Lobby {lobby}", lobbyId.Key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DistributePoseData(CancellationToken token)
|
||||||
|
{
|
||||||
|
await _lobbyPoseDataModificationSemaphore.WaitAsync(token).ConfigureAwait(false);
|
||||||
|
Dictionary<string, Dictionary<string, PoseData>> clone = [];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
clone = _lobbyPoseData.ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal);
|
||||||
|
_lobbyPoseData.Clear();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during Distributing Pose Data Clone generation");
|
||||||
|
_lobbyPoseData.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lobbyPoseDataModificationSemaphore.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var lobbyId in clone)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!lobbyId.Value.Values.Any())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var gposeLobbyUsers = await _redisDb.GetAsync<List<string>>($"GposeLobby:{lobbyId.Key}").ConfigureAwait(false);
|
||||||
|
if (gposeLobbyUsers == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var data in lobbyId.Value)
|
||||||
|
{
|
||||||
|
await _hubContext.Clients.Users(gposeLobbyUsers.Where(k => !string.Equals(k, data.Key, StringComparison.Ordinal)))
|
||||||
|
.Client_GposeLobbyPushPoseData(new(data.Key), data.Value).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error during Pose Data Distribution for Lobby {lobby}", lobbyId.Key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_runtimeCts.Cancel();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,6 +100,9 @@ public class Startup
|
|||||||
services.AddSingleton<CharaDataCleanupService>();
|
services.AddSingleton<CharaDataCleanupService>();
|
||||||
services.AddHostedService(provider => provider.GetService<CharaDataCleanupService>());
|
services.AddHostedService(provider => provider.GetService<CharaDataCleanupService>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
services.AddSingleton<GPoseLobbyDistributionService>();
|
||||||
|
services.AddHostedService(provider => provider.GetService<GPoseLobbyDistributionService>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConfigureSignalR(IServiceCollection services, IConfigurationSection mareConfig)
|
private static void ConfigureSignalR(IServiceCollection services, IConfigurationSection mareConfig)
|
||||||
@@ -276,6 +279,8 @@ public class Startup
|
|||||||
MetricsAPI.GaugeGroupPairs,
|
MetricsAPI.GaugeGroupPairs,
|
||||||
MetricsAPI.GaugeGroupPairsPaused,
|
MetricsAPI.GaugeGroupPairsPaused,
|
||||||
MetricsAPI.GaugeUsersRegistered,
|
MetricsAPI.GaugeUsersRegistered,
|
||||||
|
MetricsAPI.GaugeGposeLobbies,
|
||||||
|
MetricsAPI.GaugeGposeLobbyUsers
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -41,4 +41,6 @@ public class MetricsAPI
|
|||||||
public const string CounterFileRequests = "mare_files_requests";
|
public const string CounterFileRequests = "mare_files_requests";
|
||||||
public const string CounterFileRequestSize = "mare_files_request_size";
|
public const string CounterFileRequestSize = "mare_files_request_size";
|
||||||
public const string CounterAccountsCreated = "mare_accounts_created";
|
public const string CounterAccountsCreated = "mare_accounts_created";
|
||||||
|
public const string GaugeGposeLobbies = "mare_gpose_lobbies";
|
||||||
|
public const string GaugeGposeLobbyUsers = "mare_gpose_lobby_users";
|
||||||
}
|
}
|
||||||
@@ -36,10 +36,6 @@ namespace MareSynchronosServer.Migrations
|
|||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("is_banned");
|
.HasColumnName("is_banned");
|
||||||
|
|
||||||
b.Property<bool>("MarkForBan")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("mark_for_ban");
|
|
||||||
|
|
||||||
b.Property<string>("PrimaryUserUID")
|
b.Property<string>("PrimaryUserUID")
|
||||||
.HasColumnType("character varying(10)")
|
.HasColumnType("character varying(10)")
|
||||||
.HasColumnName("primary_user_uid");
|
.HasColumnName("primary_user_uid");
|
||||||
@@ -332,6 +328,26 @@ namespace MareSynchronosServer.Migrations
|
|||||||
.HasColumnType("character varying(10)")
|
.HasColumnType("character varying(10)")
|
||||||
.HasColumnName("other_user_uid");
|
.HasColumnName("other_user_uid");
|
||||||
|
|
||||||
|
b.Property<bool>("AllowReceivingMessages")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("allow_receiving_messages");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableAnimations")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_animations");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableSounds")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_sounds");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableVFX")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_vfx");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPaused")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("is_paused");
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
b.Property<byte[]>("Timestamp")
|
||||||
.IsConcurrencyToken()
|
.IsConcurrencyToken()
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
@@ -357,10 +373,6 @@ namespace MareSynchronosServer.Migrations
|
|||||||
.HasColumnType("character varying(40)")
|
.HasColumnType("character varying(40)")
|
||||||
.HasColumnName("hash");
|
.HasColumnName("hash");
|
||||||
|
|
||||||
b.Property<long>("RawSize")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("raw_size");
|
|
||||||
|
|
||||||
b.Property<long>("Size")
|
b.Property<long>("Size")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.HasColumnName("size");
|
.HasColumnName("size");
|
||||||
@@ -429,6 +441,18 @@ namespace MareSynchronosServer.Migrations
|
|||||||
.HasColumnType("character varying(50)")
|
.HasColumnType("character varying(50)")
|
||||||
.HasColumnName("alias");
|
.HasColumnName("alias");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableAnimations")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_animations");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableSounds")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_sounds");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableVFX")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_vfx");
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
b.Property<string>("HashedPassword")
|
||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
.HasColumnName("hashed_password");
|
.HasColumnName("hashed_password");
|
||||||
@@ -441,18 +465,6 @@ namespace MareSynchronosServer.Migrations
|
|||||||
.HasColumnType("character varying(10)")
|
.HasColumnType("character varying(10)")
|
||||||
.HasColumnName("owner_uid");
|
.HasColumnName("owner_uid");
|
||||||
|
|
||||||
b.Property<bool>("PreferDisableAnimations")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("prefer_disable_animations");
|
|
||||||
|
|
||||||
b.Property<bool>("PreferDisableSounds")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("prefer_disable_sounds");
|
|
||||||
|
|
||||||
b.Property<bool>("PreferDisableVFX")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("prefer_disable_vfx");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
b.HasKey("GID")
|
||||||
.HasName("pk_groups");
|
.HasName("pk_groups");
|
||||||
|
|
||||||
@@ -509,10 +521,26 @@ namespace MareSynchronosServer.Migrations
|
|||||||
.HasColumnType("character varying(10)")
|
.HasColumnType("character varying(10)")
|
||||||
.HasColumnName("group_user_uid");
|
.HasColumnName("group_user_uid");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableAnimations")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_animations");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableSounds")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_sounds");
|
||||||
|
|
||||||
|
b.Property<bool>("DisableVFX")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("disable_vfx");
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
b.Property<bool>("IsModerator")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("is_moderator");
|
.HasColumnName("is_moderator");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPaused")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("is_paused");
|
||||||
|
|
||||||
b.Property<bool>("IsPinned")
|
b.Property<bool>("IsPinned")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("is_pinned");
|
.HasColumnName("is_pinned");
|
||||||
@@ -529,44 +557,6 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.ToTable("group_pairs", (string)null);
|
b.ToTable("group_pairs", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPairPreferredPermission", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableAnimations")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_animations");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableSounds")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_sounds");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableVFX")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_vfx");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "GroupGID")
|
|
||||||
.HasName("pk_group_pair_preferred_permissions");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pair_preferred_permissions_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_group_pair_preferred_permissions_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pair_preferred_permissions", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("GroupGID")
|
b.Property<string>("GroupGID")
|
||||||
@@ -664,95 +654,6 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.ToTable("users", (string)null);
|
b.ToTable("users", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.UserDefaultPreferredPermission", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableGroupAnimations")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_group_animations");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableGroupSounds")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_group_sounds");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableGroupVFX")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_group_vfx");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableIndividualAnimations")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_individual_animations");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableIndividualSounds")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_individual_sounds");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableIndividualVFX")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_individual_vfx");
|
|
||||||
|
|
||||||
b.Property<bool>("IndividualIsSticky")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("individual_is_sticky");
|
|
||||||
|
|
||||||
b.HasKey("UserUID")
|
|
||||||
.HasName("pk_user_default_preferred_permissions");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_user_default_preferred_permissions_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("user_default_preferred_permissions", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.UserPermissionSet", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableAnimations")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_animations");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableSounds")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_sounds");
|
|
||||||
|
|
||||||
b.Property<bool>("DisableVFX")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("disable_vfx");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<bool>("Sticky")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("sticky");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_user_permission_sets");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_user_permission_sets_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_user_permission_sets_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID", "OtherUserUID", "IsPaused")
|
|
||||||
.HasDatabaseName("ix_user_permission_sets_user_uid_other_user_uid_is_paused");
|
|
||||||
|
|
||||||
b.ToTable("user_permission_sets", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.UserProfileData", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.UserProfileData", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("UserUID")
|
b.Property<string>("UserUID")
|
||||||
@@ -785,6 +686,43 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.ToTable("user_profile_data", (string)null);
|
b.ToTable("user_profile_data", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.UserProfileDataReport", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("ReportDate")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("report_date");
|
||||||
|
|
||||||
|
b.Property<string>("ReportReason")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("report_reason");
|
||||||
|
|
||||||
|
b.Property<string>("ReportedUserUID")
|
||||||
|
.HasColumnType("character varying(10)")
|
||||||
|
.HasColumnName("reported_user_uid");
|
||||||
|
|
||||||
|
b.Property<string>("ReportingUserUID")
|
||||||
|
.HasColumnType("character varying(10)")
|
||||||
|
.HasColumnName("reporting_user_uid");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_user_profile_data_reports");
|
||||||
|
|
||||||
|
b.HasIndex("ReportedUserUID")
|
||||||
|
.HasDatabaseName("ix_user_profile_data_reports_reported_user_uid");
|
||||||
|
|
||||||
|
b.HasIndex("ReportingUserUID")
|
||||||
|
.HasDatabaseName("ix_user_profile_data_reports_reporting_user_uid");
|
||||||
|
|
||||||
|
b.ToTable("user_profile_data_reports", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "PrimaryUser")
|
b.HasOne("MareSynchronosShared.Models.User", "PrimaryUser")
|
||||||
@@ -988,27 +926,6 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.Navigation("GroupUser");
|
b.Navigation("GroupUser");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPairPreferredPermission", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pair_preferred_permissions_groups_group_gid");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pair_preferred_permissions_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
||||||
@@ -1031,39 +948,6 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.Navigation("User");
|
b.Navigation("User");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.UserDefaultPreferredPermission", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_user_default_preferred_permissions_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.UserPermissionSet", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_user_permission_sets_users_other_user_uid");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_user_permission_sets_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.UserProfileData", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.UserProfileData", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
b.HasOne("MareSynchronosShared.Models.User", "User")
|
||||||
@@ -1076,6 +960,23 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.Navigation("User");
|
b.Navigation("User");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.UserProfileDataReport", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("MareSynchronosShared.Models.User", "ReportedUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ReportedUserUID")
|
||||||
|
.HasConstraintName("fk_user_profile_data_reports_users_reported_user_uid");
|
||||||
|
|
||||||
|
b.HasOne("MareSynchronosShared.Models.User", "ReportingUser")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ReportingUserUID")
|
||||||
|
.HasConstraintName("fk_user_profile_data_reports_users_reporting_user_uid");
|
||||||
|
|
||||||
|
b.Navigation("ReportedUser");
|
||||||
|
|
||||||
|
b.Navigation("ReportingUser");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.CharaData", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.CharaData", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("AllowedIndividiuals");
|
b.Navigation("AllowedIndividiuals");
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ public class AuthServiceConfiguration : MareConfigurationBase
|
|||||||
public int RegisterIpLimit { get; set; } = 3;
|
public int RegisterIpLimit { get; set; } = 3;
|
||||||
public int RegisterIpDurationInMinutes { get; set; } = 10;
|
public int RegisterIpDurationInMinutes { get; set; } = 10;
|
||||||
|
|
||||||
|
public string WellKnown { get; set; } = string.Empty;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
@@ -21,6 +23,7 @@ public class AuthServiceConfiguration : MareConfigurationBase
|
|||||||
sb.AppendLine($"{nameof(UseGeoIP)} => {UseGeoIP}");
|
sb.AppendLine($"{nameof(UseGeoIP)} => {UseGeoIP}");
|
||||||
sb.AppendLine($"{nameof(RegisterIpLimit)} => {RegisterIpLimit}");
|
sb.AppendLine($"{nameof(RegisterIpLimit)} => {RegisterIpLimit}");
|
||||||
sb.AppendLine($"{nameof(RegisterIpDurationInMinutes)} => {RegisterIpDurationInMinutes}");
|
sb.AppendLine($"{nameof(RegisterIpDurationInMinutes)} => {RegisterIpDurationInMinutes}");
|
||||||
|
sb.AppendLine($"{nameof(WellKnown)} => {WellKnown}");
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user