voice chat [TEST]
This commit is contained in:
parent
bf8659b8cd
commit
2ca092b017
6 changed files with 226 additions and 51 deletions
|
|
@ -1038,6 +1038,24 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
|||
, password));
|
||||
break;
|
||||
}
|
||||
case "room/voice/join":
|
||||
await context.Response.WriteAsync(
|
||||
Encryption.Encryption.EncryptString(
|
||||
await Room.Shared.VoiceJoin(id, serializedBody.string2)
|
||||
, password));
|
||||
break;
|
||||
case "room/voice/leave":
|
||||
await context.Response.WriteAsync(
|
||||
Encryption.Encryption.EncryptString(
|
||||
await Room.Shared.VoiceLeave(id, serializedBody.string2)
|
||||
, password));
|
||||
break;
|
||||
case "room/signal":
|
||||
await context.Response.WriteAsync(
|
||||
Encryption.Encryption.EncryptString(
|
||||
await Room.Shared.RoomSignal(id, serializedBody.string2)
|
||||
, password));
|
||||
break;
|
||||
case "group/message/react/remove":
|
||||
{
|
||||
Universal3String msgReact = JsonSerializer.Deserialize(
|
||||
|
|
@ -1166,10 +1184,19 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
|||
return;
|
||||
}
|
||||
|
||||
await context.Response.WriteAsync(
|
||||
Encryption.Encryption.EncryptString(
|
||||
await Utils.UpdateUserPublicStorageEntryRaw(id, target, fileBytes)
|
||||
, password));
|
||||
SemaphoreSlim userLock = Utils.GetUserLock(id);
|
||||
await userLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
await context.Response.WriteAsync(
|
||||
Encryption.Encryption.EncryptString(
|
||||
await Utils.UpdateUserPublicStorageEntryRaw(id, target, fileBytes)
|
||||
, password));
|
||||
}
|
||||
finally
|
||||
{
|
||||
userLock.Release();
|
||||
}
|
||||
}
|
||||
public static async Task UploadDmAttachmentStaging(HttpContext context, Func<Task> next, IQueryCollection query)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -379,24 +379,15 @@ public class Utils
|
|||
|
||||
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/public";
|
||||
string path = $"{dirPath}/{entry}";
|
||||
SemaphoreSlim userLock = GetUserLock(id);
|
||||
await userLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||
|
||||
if (currentTotalSize - fileExistingSize + contentBytes.Length > PUBLIC_STORAGE_LIMIT)
|
||||
{
|
||||
return "error:storage.limit.exceeded";
|
||||
}
|
||||
|
||||
await Fs.WriteFile(path, contentBytes);
|
||||
}
|
||||
finally
|
||||
if (currentTotalSize - fileExistingSize + contentBytes.Length > PUBLIC_STORAGE_LIMIT)
|
||||
{
|
||||
userLock.Release();
|
||||
return "error:storage.limit.exceeded";
|
||||
}
|
||||
|
||||
await Fs.WriteFile(path, contentBytes);
|
||||
return "success:storage.entry.updated";
|
||||
}
|
||||
|
||||
|
|
@ -418,24 +409,15 @@ public class Utils
|
|||
|
||||
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/public";
|
||||
string path = $"{dirPath}/{entry}";
|
||||
SemaphoreSlim userLock = GetUserLock(id);
|
||||
await userLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||
|
||||
if (currentTotalSize - fileExistingSize + contentBytes.Length > PUBLIC_STORAGE_LIMIT)
|
||||
{
|
||||
return "error:storage.limit.exceeded";
|
||||
}
|
||||
|
||||
await Fs.WriteFile(path, contentBytes);
|
||||
}
|
||||
finally
|
||||
if (currentTotalSize - fileExistingSize + contentBytes.Length > PUBLIC_STORAGE_LIMIT)
|
||||
{
|
||||
userLock.Release();
|
||||
return "error:storage.limit.exceeded";
|
||||
}
|
||||
|
||||
await Fs.WriteFile(path, contentBytes);
|
||||
return "success:storage.entry.updated";
|
||||
}
|
||||
|
||||
|
|
@ -471,24 +453,15 @@ public class Utils
|
|||
|
||||
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/private";
|
||||
string path = $"{dirPath}/{entry}";
|
||||
SemaphoreSlim userLock = GetUserLock(id);
|
||||
await userLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||
|
||||
if (currentTotalSize - fileExistingSize + contentBytes.Length > PRIVATE_STORAGE_LIMIT)
|
||||
{
|
||||
return "error:storage.limit.exceeded";
|
||||
}
|
||||
|
||||
await Fs.WriteFile(path, contentBytes);
|
||||
}
|
||||
finally
|
||||
if (currentTotalSize - fileExistingSize + contentBytes.Length > PRIVATE_STORAGE_LIMIT)
|
||||
{
|
||||
userLock.Release();
|
||||
return "error:storage.limit.exceeded";
|
||||
}
|
||||
|
||||
await Fs.WriteFile(path, contentBytes);
|
||||
return "success:storage.entry.updated";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -600,4 +600,132 @@ public class Shared
|
|||
if (roomType == "groups") return "group";
|
||||
return "room";
|
||||
}
|
||||
|
||||
public static async Task<string> VoiceJoin(string id, string body)
|
||||
{
|
||||
Universal2String serializedBody = JsonSerializer.Deserialize(
|
||||
body,
|
||||
AppJsonSerializerContext.Default.Universal2String
|
||||
);
|
||||
string roomType = serializedBody.string1;
|
||||
string roomId = serializedBody.string2;
|
||||
|
||||
if (!await IsMemberOfRoom(id, roomType, roomId)) return "error:forbidden";
|
||||
|
||||
var callList = ActiveCalls.GetOrAdd(roomId, _ => new List<string>());
|
||||
lock (callList)
|
||||
{
|
||||
if (!callList.Contains(id))
|
||||
{
|
||||
callList.Add(id);
|
||||
}
|
||||
}
|
||||
|
||||
string callState;
|
||||
lock (callList) { callState = JsonSerializer.Serialize(callList, AppJsonSerializerContext.Default.ListString); }
|
||||
|
||||
string bestIp = "";
|
||||
long bestLoad = long.MaxValue;
|
||||
|
||||
foreach (var ip in VOICE_IPS)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = new System.Net.Http.HttpClient();
|
||||
client.Timeout = TimeSpan.FromSeconds(2);
|
||||
string url = ip.StartsWith("http") ? ip : $"http://{ip}";
|
||||
string loadStr = await client.GetStringAsync($"{url}/load");
|
||||
if (long.TryParse(loadStr, out long load))
|
||||
{
|
||||
if (load < bestLoad)
|
||||
{
|
||||
bestLoad = load;
|
||||
bestIp = ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(bestIp))
|
||||
{
|
||||
if (VOICE_IPS.Count > 0) bestIp = VOICE_IPS.First();
|
||||
else return "error:no.voice.servers";
|
||||
}
|
||||
|
||||
string[] members = Fs.ReadDirectory($"{GetRoomPath(roomType, roomId)}/members");
|
||||
foreach(string memberWD in members)
|
||||
{
|
||||
if (Account.Utils.IsUserLocal(memberWD, out string _))
|
||||
{
|
||||
string memberId = Account.Utils.GetValidIdOrZero(memberWD);
|
||||
_ = Utils.Utils.SendWsMessage(memberId, $"call_update:{roomId}:{callState}");
|
||||
}
|
||||
}
|
||||
return $"success:{bestIp}";
|
||||
}
|
||||
|
||||
public static async Task<string> VoiceLeave(string id, string body)
|
||||
{
|
||||
Universal2String serializedBody = JsonSerializer.Deserialize(
|
||||
body,
|
||||
AppJsonSerializerContext.Default.Universal2String
|
||||
);
|
||||
string roomType = serializedBody.string1;
|
||||
string roomId = serializedBody.string2;
|
||||
|
||||
if (ActiveCalls.TryGetValue(roomId, out var callList))
|
||||
{
|
||||
bool removed = false;
|
||||
lock (callList)
|
||||
{
|
||||
if (callList.Contains(id))
|
||||
{
|
||||
callList.Remove(id);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed)
|
||||
{
|
||||
string callState;
|
||||
lock (callList) { callState = JsonSerializer.Serialize(callList, AppJsonSerializerContext.Default.ListString); }
|
||||
|
||||
string[] members = Fs.ReadDirectory($"{GetRoomPath(roomType, roomId)}/members");
|
||||
foreach(string memberWD in members)
|
||||
{
|
||||
if (Account.Utils.IsUserLocal(memberWD, out string _))
|
||||
{
|
||||
string memberId = Account.Utils.GetValidIdOrZero(memberWD);
|
||||
_ = Utils.Utils.SendWsMessage(memberId, $"call_update:{roomId}:{callState}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "success";
|
||||
}
|
||||
|
||||
public static async Task<string> RoomSignal(string id, string body)
|
||||
{
|
||||
Universal3String serializedBody = JsonSerializer.Deserialize(
|
||||
body,
|
||||
AppJsonSerializerContext.Default.Universal3String
|
||||
);
|
||||
string roomType = serializedBody.string1;
|
||||
string roomId = serializedBody.string2;
|
||||
string signalPayload = serializedBody.string3;
|
||||
|
||||
if (!await IsMemberOfRoom(id, roomType, roomId)) return "error:forbidden";
|
||||
|
||||
string[] members = Fs.ReadDirectory($"{GetRoomPath(roomType, roomId)}/members");
|
||||
foreach(string memberWD in members)
|
||||
{
|
||||
if (Account.Utils.IsUserLocal(memberWD, out string _))
|
||||
{
|
||||
string memberId = Account.Utils.GetValidIdOrZero(memberWD);
|
||||
_ = Utils.Utils.SendWsMessage(memberId, $"signal:{roomId}:{signalPayload}");
|
||||
}
|
||||
}
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ using System.Collections.Generic;
|
|||
[JsonSerializable(typeof(Dictionary<string, string>))]
|
||||
[JsonSerializable(typeof(GroupKeyRotationPayload))]
|
||||
[JsonSerializable(typeof(string[]))]
|
||||
[JsonSerializable(typeof(List<string>))]
|
||||
public partial class AppJsonSerializerContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ public class Utils
|
|||
};
|
||||
|
||||
public static ConcurrentDictionary<string, List<System.Net.WebSockets.WebSocket>> ActiveWebSockets = new();
|
||||
public static ConcurrentDictionary<string, List<string>> ActiveCalls = new();
|
||||
|
||||
public static async Task WsHandler(HttpContext context, System.Net.WebSockets.WebSocket webSocket, IQueryCollection query)
|
||||
{
|
||||
|
|
@ -168,6 +169,39 @@ public class Utils
|
|||
{
|
||||
await webSocket.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
|
||||
}
|
||||
|
||||
// Check if user was in any call and remove them
|
||||
foreach (var kvp in ActiveCalls)
|
||||
{
|
||||
bool removed = false;
|
||||
lock (kvp.Value)
|
||||
{
|
||||
if (kvp.Value.Contains(id))
|
||||
{
|
||||
kvp.Value.Remove(id);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed)
|
||||
{
|
||||
string callState;
|
||||
lock (kvp.Value) { callState = JsonSerializer.Serialize(kvp.Value, AppJsonSerializerContext.Default.ListString); }
|
||||
|
||||
// Broadcast to all room members
|
||||
string[] members = Fs.ReadDirectory($"{ROOMS_DIR}/dms/{DOMAIN}/{kvp.Key}/members");
|
||||
if (members.Length == 0) members = Fs.ReadDirectory($"{ROOMS_DIR}/groups/{DOMAIN}/{kvp.Key}/members");
|
||||
|
||||
foreach (string memberWD in members)
|
||||
{
|
||||
if (Account.Utils.IsUserLocal(memberWD, out string _))
|
||||
{
|
||||
string memberId = Account.Utils.GetValidIdOrZero(memberWD);
|
||||
_ = SendWsMessage(memberId, $"call_update:{kvp.Key}:{callState}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +299,13 @@ public class Utils
|
|||
if (parts.Length == 2)
|
||||
{
|
||||
var key = parts[0].Trim();
|
||||
var val = parts[1].Trim();
|
||||
var val = parts[1];
|
||||
int commentIndex = val.IndexOf('#');
|
||||
if (commentIndex >= 0)
|
||||
{
|
||||
val = val.Substring(0, commentIndex);
|
||||
}
|
||||
val = val.Trim();
|
||||
|
||||
Environment.SetEnvironmentVariable(key, val);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,13 @@ public class Utils
|
|||
if (parts.Length == 2)
|
||||
{
|
||||
var key = parts[0].Trim();
|
||||
var val = parts[1].Trim();
|
||||
var val = parts[1];
|
||||
int commentIndex = val.IndexOf('#');
|
||||
if (commentIndex >= 0)
|
||||
{
|
||||
val = val.Substring(0, commentIndex);
|
||||
}
|
||||
val = val.Trim();
|
||||
|
||||
Environment.SetEnvironmentVariable(key, val);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue