diff --git a/application-server/dotnet/.gitignore b/application-server/dotnet/.gitignore new file mode 100644 index 00000000..06262728 --- /dev/null +++ b/application-server/dotnet/.gitignore @@ -0,0 +1,37 @@ +*.swp +*.*~ +project.lock.json +.DS_Store +*.pyc +nupkg/ + +# Visual Studio Code +.vscode + +# Rider +.idea + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +msbuild.log +msbuild.err +msbuild.wrn + +# Visual Studio 2015 +.vs/ \ No newline at end of file diff --git a/application-server/dotnet/Program.cs b/application-server/dotnet/Program.cs new file mode 100644 index 00000000..6f674e2d --- /dev/null +++ b/application-server/dotnet/Program.cs @@ -0,0 +1,77 @@ +using System.Text; +using System.IdentityModel.Tokens.Jwt; +using Microsoft.IdentityModel.Tokens; +using System.Text.Json; + +var builder = WebApplication.CreateBuilder(args); + +var MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; + +IConfiguration config = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json") + .AddEnvironmentVariables().Build(); + +// Load env variables +var SERVER_PORT = config.GetValue("SERVER_PORT"); +var LIVEKIT_API_KEY = config.GetValue("LIVEKIT_API_KEY"); +var LIVEKIT_API_SECRET = config.GetValue("LIVEKIT_API_SECRET"); + +// Enable CORS support +builder.Services.AddCors(options => +{ + options.AddPolicy(name: MyAllowSpecificOrigins, + builder => + { + builder.WithOrigins("*").AllowAnyHeader(); + }); +}); + +builder.WebHost.UseKestrel(serverOptions => +{ + serverOptions.ListenAnyIP(SERVER_PORT); +}); + +var app = builder.Build(); +app.UseCors(MyAllowSpecificOrigins); + +app.MapPost("/token", async (HttpRequest request) => +{ + var body = new StreamReader(request.Body); + string postData = await body.ReadToEndAsync(); + Dictionary bodyParams = JsonSerializer.Deserialize>(postData) ?? new Dictionary(); + + if (bodyParams.TryGetValue("roomName", out var roomName) && bodyParams.TryGetValue("participantName", out var participantName)) + { + var token = CreateLiveKitJWT(roomName.ToString(), participantName.ToString()); + return Results.Json(token); + } + else + { + return Results.BadRequest("\"roomName\" and \"participantName\" are required"); + } +}); + +string CreateLiveKitJWT(string roomName, string participantName) +{ + JwtHeader headers = new(new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(LIVEKIT_API_SECRET)), "HS256")); + + var videoGrants = new Dictionary() + { + { "room", roomName }, + { "roomJoin", true } + }; + JwtPayload payload = new() + { + { "exp", new DateTimeOffset(DateTime.UtcNow.AddHours(6)).ToUnixTimeSeconds() }, + { "iss", LIVEKIT_API_KEY }, + { "nbf", 0 }, + { "sub", participantName }, + { "name", participantName }, + { "video", videoGrants } + }; + JwtSecurityToken token = new(headers, payload); + return new JwtSecurityTokenHandler().WriteToken(token); +} + +app.Run(); \ No newline at end of file diff --git a/application-server/dotnet/Properties/launchSettings.json b/application-server/dotnet/Properties/launchSettings.json new file mode 100644 index 00000000..32d5a528 --- /dev/null +++ b/application-server/dotnet/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:6080", + "sslPort": 6080 + } + }, + "profiles": { + "openvidu_basic_dotnet": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://0.0.0.0:6080", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/application-server/dotnet/appsettings.json b/application-server/dotnet/appsettings.json new file mode 100644 index 00000000..3ea29ee5 --- /dev/null +++ b/application-server/dotnet/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "SERVER_PORT": 6080, + "LIVEKIT_API_KEY": "devkey", + "LIVEKIT_API_SECRET": "secret" +} diff --git a/application-server/dotnet/dotnet.sln b/application-server/dotnet/dotnet.sln new file mode 100644 index 00000000..ad4e8d7b --- /dev/null +++ b/application-server/dotnet/dotnet.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet8", "dotnet8.csproj", "{DA3ECE3C-C14D-4E3A-A81C-91408791DC8E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA3ECE3C-C14D-4E3A-A81C-91408791DC8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA3ECE3C-C14D-4E3A-A81C-91408791DC8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA3ECE3C-C14D-4E3A-A81C-91408791DC8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA3ECE3C-C14D-4E3A-A81C-91408791DC8E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {10EC1ABF-606B-4007-B8DA-11FADFE7B3BC} + EndGlobalSection +EndGlobal diff --git a/application-server/dotnet/dotnet8.csproj b/application-server/dotnet/dotnet8.csproj new file mode 100644 index 00000000..95fca14a --- /dev/null +++ b/application-server/dotnet/dotnet8.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/application-server/java/src/main/java/io/openvidu/basic/java/Controller.java b/application-server/java/src/main/java/io/openvidu/basic/java/Controller.java index 7e7e2661..6f00b7bf 100644 --- a/application-server/java/src/main/java/io/openvidu/basic/java/Controller.java +++ b/application-server/java/src/main/java/io/openvidu/basic/java/Controller.java @@ -25,10 +25,7 @@ public class Controller { * @param params JSON object with roomName and participantName * @return The JWT token */ - @PostMapping( - value = "/token", - produces = "application/json" - ) + @PostMapping(value = "/token", produces = "application/json") public ResponseEntity getToken(@RequestBody Map params) { String roomName = params.get("roomName"); String participantName = params.get("participantName"); diff --git a/application-server/node/package-lock.json b/application-server/node/package-lock.json index 7487f540..0df2f47a 100644 --- a/application-server/node/package-lock.json +++ b/application-server/node/package-lock.json @@ -11,7 +11,7 @@ "cors": "2.8.5", "dotenv": "16.4.5", "express": "4.19.2", - "livekit-server-sdk": "2.1.2" + "livekit-server-sdk": "2.3.0" } }, "node_modules/@bufbuild/protobuf": { @@ -20,9 +20,9 @@ "integrity": "sha512-W7gp8Q/v1NlCZLsv8pQ3Y0uCu/SHgXOVFK+eUluUKWXmsb6VHkpNx0apdOWWcDbB9sJoKeP8uPrjmehJz6xETQ==" }, "node_modules/@livekit/protocol": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@livekit/protocol/-/protocol-1.13.0.tgz", - "integrity": "sha512-M3U36VgRfb0VutWG6pnozXusL+mkYstbCctTLUyCIyye36Ztv1wA9zYpyYvz7VnsgmCn+g/g0eB2rnAkTVwcnA==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@livekit/protocol/-/protocol-1.15.0.tgz", + "integrity": "sha512-KVjM1odPzEWkXB4QQyz2qfiecHo74wLeb8YDhaX/cNnxUk0H1L35H0gVgLA8Y6fXkF3ayOHQnXO9V3GzulMyXw==", "dependencies": { "@bufbuild/protobuf": "^1.7.2" } @@ -94,28 +94,28 @@ } }, "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/camelcase-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", - "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-9.1.3.tgz", + "integrity": "sha512-Rircqi9ch8AnZscQcsA1C47NFdaO3wukpmIRzYcDOrmvgt78hM/sj5pZhZNec2NM12uk5vTwRHZ4anGcrC4ZTg==", "dependencies": { - "camelcase": "^6.3.0", - "map-obj": "^4.1.0", - "quick-lru": "^5.1.1", - "type-fest": "^1.2.1" + "camelcase": "^8.0.0", + "map-obj": "5.0.0", + "quick-lru": "^6.1.1", + "type-fest": "^4.3.2" }, "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -465,24 +465,24 @@ } }, "node_modules/livekit-server-sdk": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/livekit-server-sdk/-/livekit-server-sdk-2.1.2.tgz", - "integrity": "sha512-ypevnVMsy5Sse2vR81BOx/P0PdV3NOj6kASkS4fyA/xiZEiFaOEa1SxJzREcs456hNGSiLkn/RrGcwk1ytaTuA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/livekit-server-sdk/-/livekit-server-sdk-2.3.0.tgz", + "integrity": "sha512-JYOM4YXGctd4fcjr1mINcmDDV5PvCIY5isNVB1Ej1kTrNwQcx7NVWTj79kDAOaMNt+CbMb3XcHEo5Hgub9BmAQ==", "dependencies": { - "@livekit/protocol": "^1.12.0", - "camelcase-keys": "^7.0.0", + "@livekit/protocol": "^1.14.0", + "camelcase-keys": "^9.0.0", "jose": "^5.1.2" }, "engines": { - "node": ">=18" + "node": ">=19" } }, "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz", + "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -619,11 +619,11 @@ } }, "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz", + "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -772,11 +772,11 @@ } }, "node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz", + "integrity": "sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==", "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" diff --git a/application-server/node/package.json b/application-server/node/package.json index 75fdbb4c..5611ec91 100644 --- a/application-server/node/package.json +++ b/application-server/node/package.json @@ -11,6 +11,6 @@ "cors": "2.8.5", "dotenv": "16.4.5", "express": "4.19.2", - "livekit-server-sdk": "2.1.2" + "livekit-server-sdk": "2.3.0" } }