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));
|
, password));
|
||||||
break;
|
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":
|
case "group/message/react/remove":
|
||||||
{
|
{
|
||||||
Universal3String msgReact = JsonSerializer.Deserialize(
|
Universal3String msgReact = JsonSerializer.Deserialize(
|
||||||
|
|
@ -1166,11 +1184,20 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SemaphoreSlim userLock = Utils.GetUserLock(id);
|
||||||
|
await userLock.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
await context.Response.WriteAsync(
|
await context.Response.WriteAsync(
|
||||||
Encryption.Encryption.EncryptString(
|
Encryption.Encryption.EncryptString(
|
||||||
await Utils.UpdateUserPublicStorageEntryRaw(id, target, fileBytes)
|
await Utils.UpdateUserPublicStorageEntryRaw(id, target, fileBytes)
|
||||||
, password));
|
, password));
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
userLock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
public static async Task UploadDmAttachmentStaging(HttpContext context, Func<Task> next, IQueryCollection query)
|
public static async Task UploadDmAttachmentStaging(HttpContext context, Func<Task> next, IQueryCollection query)
|
||||||
{
|
{
|
||||||
if (!query.TryGetValue("id", out var idQuery)) return;
|
if (!query.TryGetValue("id", out var idQuery)) return;
|
||||||
|
|
|
||||||
|
|
@ -379,10 +379,6 @@ public class Utils
|
||||||
|
|
||||||
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/public";
|
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/public";
|
||||||
string path = $"{dirPath}/{entry}";
|
string path = $"{dirPath}/{entry}";
|
||||||
SemaphoreSlim userLock = GetUserLock(id);
|
|
||||||
await userLock.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||||
|
|
||||||
|
|
@ -392,11 +388,6 @@ public class Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
await Fs.WriteFile(path, contentBytes);
|
await Fs.WriteFile(path, contentBytes);
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
userLock.Release();
|
|
||||||
}
|
|
||||||
return "success:storage.entry.updated";
|
return "success:storage.entry.updated";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -418,10 +409,6 @@ public class Utils
|
||||||
|
|
||||||
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/public";
|
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/public";
|
||||||
string path = $"{dirPath}/{entry}";
|
string path = $"{dirPath}/{entry}";
|
||||||
SemaphoreSlim userLock = GetUserLock(id);
|
|
||||||
await userLock.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||||
|
|
||||||
|
|
@ -431,11 +418,6 @@ public class Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
await Fs.WriteFile(path, contentBytes);
|
await Fs.WriteFile(path, contentBytes);
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
userLock.Release();
|
|
||||||
}
|
|
||||||
return "success:storage.entry.updated";
|
return "success:storage.entry.updated";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -471,10 +453,6 @@ public class Utils
|
||||||
|
|
||||||
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/private";
|
string dirPath = $"{ACCOUNTS_DATA_DIR}/{id}/storage/private";
|
||||||
string path = $"{dirPath}/{entry}";
|
string path = $"{dirPath}/{entry}";
|
||||||
SemaphoreSlim userLock = GetUserLock(id);
|
|
||||||
await userLock.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
long currentTotalSize = LarpixServer.Utils.Utils.GetDirectorySize(dirPath);
|
||||||
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
long fileExistingSize = File.Exists(path) ? new FileInfo(path).Length : 0;
|
||||||
|
|
||||||
|
|
@ -484,11 +462,6 @@ public class Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
await Fs.WriteFile(path, contentBytes);
|
await Fs.WriteFile(path, contentBytes);
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
userLock.Release();
|
|
||||||
}
|
|
||||||
return "success:storage.entry.updated";
|
return "success:storage.entry.updated";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -600,4 +600,132 @@ public class Shared
|
||||||
if (roomType == "groups") return "group";
|
if (roomType == "groups") return "group";
|
||||||
return "room";
|
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(Dictionary<string, string>))]
|
||||||
[JsonSerializable(typeof(GroupKeyRotationPayload))]
|
[JsonSerializable(typeof(GroupKeyRotationPayload))]
|
||||||
[JsonSerializable(typeof(string[]))]
|
[JsonSerializable(typeof(string[]))]
|
||||||
|
[JsonSerializable(typeof(List<string>))]
|
||||||
public partial class AppJsonSerializerContext : JsonSerializerContext
|
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<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)
|
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);
|
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)
|
if (parts.Length == 2)
|
||||||
{
|
{
|
||||||
var key = parts[0].Trim();
|
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);
|
Environment.SetEnvironmentVariable(key, val);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,13 @@ public class Utils
|
||||||
if (parts.Length == 2)
|
if (parts.Length == 2)
|
||||||
{
|
{
|
||||||
var key = parts[0].Trim();
|
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);
|
Environment.SetEnvironmentVariable(key, val);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue