Compare commits
	
		
			2 Commits
		
	
	
		
			bec294365f
			...
			b12e3315fe
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b12e3315fe | |||
| da4ee81c95 | 
| @@ -40,8 +40,7 @@ public class CloudflareRealtimeService : IRealtimeService | |||||||
|         var requestBody = new |         var requestBody = new | ||||||
|         { |         { | ||||||
|             title = roomName, |             title = roomName, | ||||||
|             preferred_region = _configuration["Realtime:Cloudflare:PreferredRegion"], |             preferred_region = _configuration["Realtime:Cloudflare:PreferredRegion"] | ||||||
|             data = metadata |  | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         var content = new StringContent(JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json"); |         var content = new StringContent(JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json"); | ||||||
| @@ -106,11 +105,15 @@ public class CloudflareRealtimeService : IRealtimeService | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Participant doesn't exist, create a new one |             // Participant doesn't exist, create a new one | ||||||
|  |             var baseUrl = _configuration["BaseUrl"]; | ||||||
|             var requestBody = new |             var requestBody = new | ||||||
|             { |             { | ||||||
|                 name = "@" + account.Name, |                 name = "@" + account.Name, | ||||||
|  |                 picture = account.Profile.Picture is not null | ||||||
|  |                     ? $"{baseUrl}/api/files/{account.Profile.Picture.Id}" | ||||||
|  |                     : null, | ||||||
|                 preset_name = isAdmin ? "group_call_host" : "group_call_participant", |                 preset_name = isAdmin ? "group_call_host" : "group_call_participant", | ||||||
|                 custom_user_id = account.Id.ToString() |                 custom_participant_id = account.Id.ToString() | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             var content = new StringContent( |             var content = new StringContent( | ||||||
|   | |||||||
| @@ -6,11 +6,6 @@ using Swashbuckle.AspNetCore.Annotations; | |||||||
|  |  | ||||||
| namespace DysonNetwork.Sphere.Chat; | namespace DysonNetwork.Sphere.Chat; | ||||||
|  |  | ||||||
| public class RealtimeChatConfiguration |  | ||||||
| { |  | ||||||
|     public string Endpoint { get; set; } = null!; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| [ApiController] | [ApiController] | ||||||
| [Route("/api/chat/realtime")] | [Route("/api/chat/realtime")] | ||||||
| public class RealtimeCallController( | public class RealtimeCallController( | ||||||
| @@ -20,9 +15,6 @@ public class RealtimeCallController( | |||||||
|     IRealtimeService realtime |     IRealtimeService realtime | ||||||
| ) : ControllerBase | ) : ControllerBase | ||||||
| { | { | ||||||
|     private readonly RealtimeChatConfiguration _config = |  | ||||||
|         configuration.GetSection("RealtimeChat").Get<RealtimeChatConfiguration>()!; |  | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// This endpoint is especially designed for livekit webhooks, |     /// This endpoint is especially designed for livekit webhooks, | ||||||
|     /// for update the call participates and more. |     /// for update the call participates and more. | ||||||
| @@ -35,9 +27,9 @@ public class RealtimeCallController( | |||||||
|         using var reader = new StreamReader(Request.Body); |         using var reader = new StreamReader(Request.Body); | ||||||
|         var postData = await reader.ReadToEndAsync(); |         var postData = await reader.ReadToEndAsync(); | ||||||
|         var authHeader = Request.Headers.Authorization.ToString(); |         var authHeader = Request.Headers.Authorization.ToString(); | ||||||
|          |  | ||||||
|         await realtime.ReceiveWebhook(postData, authHeader); |         await realtime.ReceiveWebhook(postData, authHeader); | ||||||
|      |  | ||||||
|         return Ok(); |         return Ok(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -90,11 +82,17 @@ public class RealtimeCallController( | |||||||
|             return BadRequest("Call session is not properly configured."); |             return BadRequest("Call session is not properly configured."); | ||||||
|  |  | ||||||
|         var isAdmin = member.Role >= ChatMemberRole.Moderator; |         var isAdmin = member.Role >= ChatMemberRole.Moderator; | ||||||
|         var userToken = realtime.GetUserToken(currentUser, ongoingCall.SessionId, isAdmin); |         var userToken = await realtime.GetUserTokenAsync(currentUser, ongoingCall.SessionId, isAdmin); | ||||||
|  |  | ||||||
|         // Get LiveKit endpoint from configuration |         // Get LiveKit endpoint from configuration | ||||||
|         var endpoint = _config.Endpoint ?? |         var endpoint = configuration[$"Realtime:{realtime.ProviderName}:Endpoint"] ?? realtime.ProviderName switch | ||||||
|                    throw new InvalidOperationException("LiveKit endpoint configuration is missing"); |         { | ||||||
|  |             // Unusable for sure, just for placeholder | ||||||
|  |             "LiveKit" => "https://livekit.cloud", | ||||||
|  |             "Cloudflare" => "https://rtk.realtime.cloudflare.com/v2", | ||||||
|  |             // Unusable for sure, just for placeholder | ||||||
|  |             _ => "https://example.com"  | ||||||
|  |         }; | ||||||
|  |  | ||||||
|         // Create the response model |         // Create the response model | ||||||
|         var response = new JoinCallResponse |         var response = new JoinCallResponse | ||||||
| @@ -162,7 +160,7 @@ public class JoinCallResponse | |||||||
|     public string Provider { get; set; } = null!; |     public string Provider { get; set; } = null!; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// The LiveKit server endpoint |     /// The provider server endpoint | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public string Endpoint { get; set; } = null!; |     public string Endpoint { get; set; } = null!; | ||||||
|  |  | ||||||
| @@ -196,24 +194,24 @@ public class CallParticipant | |||||||
|     /// The participant's identity (username) |     /// The participant's identity (username) | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public string Identity { get; set; } = null!; |     public string Identity { get; set; } = null!; | ||||||
|      |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// The participant's display name |     /// The participant's display name | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public string Name { get; set; } = null!; |     public string Name { get; set; } = null!; | ||||||
|      |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// The participant's account ID if available |     /// The participant's account ID if available | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public Guid? AccountId { get; set; } |     public Guid? AccountId { get; set; } | ||||||
|      |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// The participant's profile in the chat |     /// The participant's profile in the chat | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public ChatMember? Profile { get; set; } |     public ChatMember? Profile { get; set; } | ||||||
|      |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// When the participant joined the call |     /// When the participant joined the call | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public DateTime JoinedAt { get; set; } |     public DateTime JoinedAt { get; set; } | ||||||
| } | } | ||||||
| @@ -31,7 +31,10 @@ public class ClientTypeMiddleware(RequestDelegate next) | |||||||
|  |  | ||||||
|         context.Items["IsWebPage"] = isWebPage; |         context.Items["IsWebPage"] = isWebPage; | ||||||
|  |  | ||||||
|         if (!isWebPage && context.Request.Path != "/ws" && !context.Request.Path.StartsWithSegments("/api")) |         var redirectWhiteList = new[] { "/ws", "/.well-known", "/swagger" }; | ||||||
|  |         if(redirectWhiteList.Any(w => context.Request.Path.StartsWithSegments(w))) | ||||||
|  |             await next(context); | ||||||
|  |         else if (!isWebPage && !context.Request.Path.StartsWithSegments("/api")) | ||||||
|             context.Response.Redirect( |             context.Response.Redirect( | ||||||
|                 $"/api{context.Request.Path.Value}{context.Request.QueryString.Value}", |                 $"/api{context.Request.Path.Value}{context.Request.QueryString.Value}", | ||||||
|                 permanent: false |                 permanent: false | ||||||
|   | |||||||
| @@ -86,7 +86,7 @@ | |||||||
|     "SubjectPrefix": "Solar Network" |     "SubjectPrefix": "Solar Network" | ||||||
|   }, |   }, | ||||||
|   "Realtime": { |   "Realtime": { | ||||||
|     "Provider": "LiveKit", |     "Provider": "Cloudflare", | ||||||
|     "LiveKit": { |     "LiveKit": { | ||||||
|       "Endpoint": "https://solar-network-im44o8gq.livekit.cloud", |       "Endpoint": "https://solar-network-im44o8gq.livekit.cloud", | ||||||
|       "ApiKey": "APIs6TiL8wj3A4j", |       "ApiKey": "APIs6TiL8wj3A4j", | ||||||
|   | |||||||
| @@ -85,6 +85,7 @@ | |||||||
| 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASourceCustom_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fdaa8d9c408cd4b4286bbef7e35f1a42e31c00_003F45_003F5839ca6c_003FSourceCustom_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASourceCustom_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fdaa8d9c408cd4b4286bbef7e35f1a42e31c00_003F45_003F5839ca6c_003FSourceCustom_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | ||||||
| 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackFrameIterator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3bef61b8a21d4c8e96872ecdd7782fa0e55000_003F7a_003F870020d0_003FStackFrameIterator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackFrameIterator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3bef61b8a21d4c8e96872ecdd7782fa0e55000_003F7a_003F870020d0_003FStackFrameIterator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | ||||||
| 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackFrameIterator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb6f0571a6bc744b0b551fd4578292582e54c00_003Fdf_003F3fcdc4d2_003FStackFrameIterator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackFrameIterator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb6f0571a6bc744b0b551fd4578292582e54c00_003Fdf_003F3fcdc4d2_003FStackFrameIterator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | ||||||
|  | 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStackFrameIterator_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe6898c1ddf974e16b95b114722270029e55000_003F6b_003F7530575d_003FStackFrameIterator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | ||||||
| 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStatusCodeResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0b5acdd962e549369896cece0026e556214600_003F7c_003F8b7572ae_003FStatusCodeResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AStatusCodeResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0b5acdd962e549369896cece0026e556214600_003F7c_003F8b7572ae_003FStatusCodeResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | ||||||
| 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASyndicationFeed_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5b43b9cf654743f8b9a2eee23c625dd21dd30_003Fad_003Fd26b4d73_003FSyndicationFeed_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASyndicationFeed_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5b43b9cf654743f8b9a2eee23c625dd21dd30_003Fad_003Fd26b4d73_003FSyndicationFeed_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | ||||||
| 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASyndicationItem_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5b43b9cf654743f8b9a2eee23c625dd21dd30_003Fe1_003Fb136d7be_003FSyndicationItem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASyndicationItem_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5b43b9cf654743f8b9a2eee23c625dd21dd30_003Fe1_003Fb136d7be_003FSyndicationItem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user