< Summary

Class:WebSocketCommunication
Assembly:WebSocketCommunication
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/KernelCommunication/WebSocketCommunication/WebSocketCommunication.cs
Covered lines:1
Uncovered lines:173
Coverable lines:174
Total lines:308
Line coverage:0.5% (1 of 174)
Covered branches:0
Total branches:0
Covered methods:1
Total methods:9
Method coverage:11.1% (1 of 9)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
WebSocketCommunication()0%110100%
WebSocketCommunication(...)0%2100%
Dispose()0%2100%
StartServer(...)0%90900%
loadSelfSignedServerCertificate()0%2100%
OnWebSocketLog(...)0%42600%
InitMessageTypeToBridgeName()0%2100%
ProcessMessages()0%3061700%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/KernelCommunication/WebSocketCommunication/WebSocketCommunication.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Net;
 5using System.Net.Sockets;
 6using System.Security.Cryptography;
 7using System.Security.Cryptography.X509Certificates;
 8using DCL;
 9using UnityEngine;
 10using WebSocketSharp;
 11using WebSocketSharp.Server;
 12
 13public class WebSocketCommunication : IKernelCommunication
 14{
 15    public static DCLWebSocketService service;
 16
 17    [System.NonSerialized]
 118    public static Queue<DCLWebSocketService.Message> queuedMessages = new Queue<DCLWebSocketService.Message>();
 19
 20    [System.NonSerialized]
 21    public static volatile bool queuedMessagesDirty;
 22
 023    private Dictionary<string, GameObject> bridgeGameObjects = new Dictionary<string, GameObject>();
 24
 025    public Dictionary<string, string> messageTypeToBridgeName = new Dictionary<string, string>(); // Public to be able t
 26    private bool requestStop = false;
 27    private Coroutine updateCoroutine;
 28
 29    WebSocketServer ws;
 30
 031    public WebSocketCommunication(bool withSSL = false, int startPort = 7666, int endPort = 7800)
 32    {
 033        InitMessageTypeToBridgeName();
 34
 035        DCL.DataStore.i.debugConfig.isWssDebugMode = true;
 36
 037        string url = StartServer(startPort, endPort, withSSL);
 38
 039        Debug.Log("WebSocket Server URL: " + url);
 40
 041        DataStore.i.wsCommunication.url = url;
 42
 043        DataStore.i.wsCommunication.communicationReady.Set(true);
 44
 045        updateCoroutine = CoroutineStarter.Start(ProcessMessages());
 046    }
 47
 048    public bool isServerReady => ws.IsListening;
 049    public void Dispose() { ws.Stop(); }
 50    public static event Action<DCLWebSocketService> OnWebSocketServiceAdded;
 51
 52    private string StartServer(int port, int maxPort, bool withSSL, bool verbose = false)
 53    {
 054        if (port > maxPort)
 55        {
 056            throw new SocketException((int)SocketError.AddressAlreadyInUse);
 57        }
 58        string wssServerUrl;
 059        string wssServiceId = "dcl";
 60        try
 61        {
 062            if (withSSL)
 63            {
 064                wssServerUrl = $"wss://localhost:{port}/";
 065                ws = new WebSocketServer(wssServerUrl)
 66                {
 67                    SslConfiguration =
 68                    {
 69                        ServerCertificate = loadSelfSignedServerCertificate(),
 70                        ClientCertificateRequired = false,
 71                        CheckCertificateRevocation = false,
 072                        ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true,
 73                        EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12
 74                    },
 75                    KeepClean = false
 76                };
 77            }
 78            else
 79            {
 080                wssServerUrl = $"ws://localhost:{port}/";
 081                ws = new WebSocketServer(wssServerUrl);
 82            }
 83
 084            ws.AddWebSocketService("/" + wssServiceId, () =>
 85            {
 086                service = new DCLWebSocketService();
 087                OnWebSocketServiceAdded?.Invoke(service);
 088                return service;
 89            });
 90
 091            if (verbose)
 92            {
 093                ws.Log.Level = LogLevel.Debug;
 094                ws.Log.Output += OnWebSocketLog;
 95            }
 096            ws.Start();
 097        }
 098        catch (InvalidOperationException e)
 99        {
 0100            ws.Stop();
 0101            if (withSSL) // Search for available ports only if we're using SSL
 102            {
 0103                SocketException se = (SocketException)e.InnerException;
 0104                if (se is { SocketErrorCode: SocketError.AddressAlreadyInUse })
 105                {
 0106                    return StartServer(port + 1, maxPort, withSSL);
 107                }
 108            }
 0109            throw new InvalidOperationException(e.Message, e.InnerException);
 110        }
 111
 0112        string wssUrl = wssServerUrl + wssServiceId;
 0113        return wssUrl;
 0114    }
 115
 116    private X509Certificate2 loadSelfSignedServerCertificate() {
 0117        byte[] rawData = Convert.FromBase64String(SelfCertificateData.data);
 0118        return new X509Certificate2(rawData, "cert");
 119    }
 120
 121    private void OnWebSocketLog(LogData logData, string message)
 122    {
 0123        switch (logData.Level)
 124        {
 125            case LogLevel.Debug:
 0126                Debug.Log($"[WebSocket] {logData.Message}");
 0127                break;
 128            case LogLevel.Warn:
 0129                Debug.LogWarning($"[WebSocket] {logData.Message}");
 0130                break;
 131            case LogLevel.Error:
 0132                Debug.LogError($"[WebSocket] {logData.Message}");
 0133                break;
 134            case LogLevel.Fatal:
 0135                Debug.LogError($"[WebSocket] {logData.Message}");
 136                break;
 137        }
 0138    }
 139
 140    private void InitMessageTypeToBridgeName()
 141    {
 142        // Please, use `Bridges` as a bridge name, avoid adding messages here. The system will use `Bridges` as the defa
 0143        messageTypeToBridgeName["SetDebug"] = "Main";
 0144        messageTypeToBridgeName["SetSceneDebugPanel"] = "Main";
 0145        messageTypeToBridgeName["SetMemoryUsage"] = "Main";
 0146        messageTypeToBridgeName["ShowFPSPanel"] = "Main";
 0147        messageTypeToBridgeName["HideFPSPanel"] = "Main";
 0148        messageTypeToBridgeName["SetEngineDebugPanel"] = "Main";
 0149        messageTypeToBridgeName["SendSceneMessage"] = "Main";
 0150        messageTypeToBridgeName["LoadParcelScenes"] = "Main";
 0151        messageTypeToBridgeName["UnloadScene"] = "Main";
 0152        messageTypeToBridgeName["UnloadSceneV2"] = "Main";
 0153        messageTypeToBridgeName["Reset"] = "Main";
 0154        messageTypeToBridgeName["CreateGlobalScene"] = "Main";
 0155        messageTypeToBridgeName["BuilderReady"] = "Main";
 0156        messageTypeToBridgeName["UpdateParcelScenes"] = "Main";
 0157        messageTypeToBridgeName["LoadProfile"] = "Main";
 0158        messageTypeToBridgeName["AddUserProfileToCatalog"] = "Main";
 0159        messageTypeToBridgeName["AddUserProfilesToCatalog"] = "Main";
 0160        messageTypeToBridgeName["RemoveUserProfilesFromCatalog"] = "Main";
 0161        messageTypeToBridgeName["ActivateRendering"] = "Main";
 0162        messageTypeToBridgeName["DeactivateRendering"] = "Main";
 0163        messageTypeToBridgeName["ForceActivateRendering"] = "Main";
 0164        messageTypeToBridgeName["AddWearablesToCatalog"] = "Main";
 0165        messageTypeToBridgeName["WearablesRequestFailed"] = "Main";
 0166        messageTypeToBridgeName["RemoveWearablesFromCatalog"] = "Main";
 0167        messageTypeToBridgeName["ClearWearableCatalog"] = "Main";
 0168        messageTypeToBridgeName["InitializeFriends"] = "Main";
 0169        messageTypeToBridgeName["UpdateFriendshipStatus"] = "Main";
 0170        messageTypeToBridgeName["UpdateUserPresence"] = "Main";
 0171        messageTypeToBridgeName["FriendNotFound"] = "Main";
 0172        messageTypeToBridgeName["UpdateMinimapSceneInformation"] = "Main";
 0173        messageTypeToBridgeName["UpdateHotScenesList"] = "Main";
 0174        messageTypeToBridgeName["SetRenderProfile"] = "Main";
 0175        messageTypeToBridgeName["CrashPayloadRequest"] = "Main";
 0176        messageTypeToBridgeName["SetDisableAssetBundles"] = "Main";
 0177        messageTypeToBridgeName["DumpRendererLockersInfo"] = "Main";
 0178        messageTypeToBridgeName["PublishSceneResult"] = "Main";
 0179        messageTypeToBridgeName["BuilderProjectInfo"] = "Main";
 0180        messageTypeToBridgeName["BuilderInWorldCatalogHeaders"] = "Main";
 0181        messageTypeToBridgeName["RequestedHeaders"] = "Main";
 0182        messageTypeToBridgeName["AddAssets"] = "Main";
 0183        messageTypeToBridgeName["RunPerformanceMeterTool"] = "Main";
 0184        messageTypeToBridgeName["InstantiateBotsAtWorldPos"] = "Main";
 0185        messageTypeToBridgeName["InstantiateBotsAtCoords"] = "Main";
 0186        messageTypeToBridgeName["StartBotsRandomizedMovement"] = "Main";
 0187        messageTypeToBridgeName["StopBotsMovement"] = "Main";
 0188        messageTypeToBridgeName["RemoveBot"] = "Main";
 0189        messageTypeToBridgeName["ClearBots"] = "Main";
 0190        messageTypeToBridgeName["ToggleSceneBoundingBoxes"] = "Main";
 0191        messageTypeToBridgeName["TogglePreviewMenu"] = "Main";
 0192        messageTypeToBridgeName["ToggleSceneSpawnPoints"] = "Main";
 0193        messageTypeToBridgeName["AddFriendsWithDirectMessages"] = "Main";
 0194        messageTypeToBridgeName["AddFriends"] = "Main";
 0195        messageTypeToBridgeName["AddFriendRequests"] = "Main";
 0196        messageTypeToBridgeName["UpdateTotalFriendRequests"] = "Main";
 0197        messageTypeToBridgeName["UpdateTotalFriends"] = "Main";
 0198        messageTypeToBridgeName["UpdateHomeScene"] = "Main";
 199
 0200        messageTypeToBridgeName["Teleport"] = "CharacterController";
 201
 0202        messageTypeToBridgeName["SetRotation"] = "CameraController";
 203
 0204        messageTypeToBridgeName["ShowNotificationFromJson"] = "HUDController";
 0205        messageTypeToBridgeName["ConfigureHUDElement"] = "HUDController";
 0206        messageTypeToBridgeName["ShowTermsOfServices"] = "HUDController";
 0207        messageTypeToBridgeName["RequestTeleport"] = "HUDController";
 0208        messageTypeToBridgeName["ShowAvatarEditorInSignUp"] = "HUDController";
 0209        messageTypeToBridgeName["SetUserTalking"] = "HUDController";
 0210        messageTypeToBridgeName["SetUsersMuted"] = "HUDController";
 0211        messageTypeToBridgeName["ShowWelcomeNotification"] = "HUDController";
 0212        messageTypeToBridgeName["UpdateBalanceOfMANA"] = "HUDController";
 0213        messageTypeToBridgeName["SetPlayerTalking"] = "HUDController";
 0214        messageTypeToBridgeName["SetVoiceChatEnabledByScene"] = "HUDController";
 0215        messageTypeToBridgeName["TriggerSelfUserExpression"] = "HUDController";
 216
 0217        messageTypeToBridgeName["GetMousePosition"] = "BuilderController";
 0218        messageTypeToBridgeName["SelectGizmo"] = "BuilderController";
 0219        messageTypeToBridgeName["ResetObject"] = "BuilderController";
 0220        messageTypeToBridgeName["ZoomDelta"] = "BuilderController";
 0221        messageTypeToBridgeName["SetPlayMode"] = "BuilderController";
 0222        messageTypeToBridgeName["TakeScreenshot"] = "BuilderController";
 0223        messageTypeToBridgeName["ResetBuilderScene"] = "BuilderController";
 0224        messageTypeToBridgeName["SetBuilderCameraPosition"] = "BuilderController";
 0225        messageTypeToBridgeName["SetBuilderCameraRotation"] = "BuilderController";
 0226        messageTypeToBridgeName["ResetBuilderCameraZoom"] = "BuilderController";
 0227        messageTypeToBridgeName["SetGridResolution"] = "BuilderController";
 0228        messageTypeToBridgeName["OnBuilderKeyDown"] = "BuilderController";
 0229        messageTypeToBridgeName["UnloadBuilderScene"] = "BuilderController";
 0230        messageTypeToBridgeName["SetSelectedEntities"] = "BuilderController";
 0231        messageTypeToBridgeName["GetCameraTargetBuilder"] = "BuilderController";
 0232        messageTypeToBridgeName["PreloadFile"] = "BuilderController";
 0233        messageTypeToBridgeName["SetBuilderConfiguration"] = "BuilderController";
 234
 0235        messageTypeToBridgeName["SetTutorialEnabled"] = "TutorialController";
 0236        messageTypeToBridgeName["SetTutorialEnabledForUsersThatAlreadyDidTheTutorial"] = "TutorialController";
 237
 0238        messageTypeToBridgeName["VoiceChatStatus"] = "VoiceChatController";
 0239    }
 240
 241    IEnumerator ProcessMessages()
 242    {
 0243        var hudControllerGO = GameObject.Find("HUDController");
 0244        var mainGO = GameObject.Find("Main");
 245
 0246        while (!requestStop)
 247        {
 0248            lock (queuedMessages)
 249            {
 0250                if (queuedMessagesDirty)
 251                {
 0252                    while (queuedMessages.Count > 0)
 253                    {
 0254                        DCLWebSocketService.Message msg = queuedMessages.Dequeue();
 255
 0256                        switch (msg.type)
 257                        {
 258                            // Add to this list the messages that are used a lot and you want better performance
 259                            case "SendSceneMessage":
 0260                                DCL.Environment.i.world.sceneController.SendSceneMessage(msg.payload);
 0261                                break;
 262                            case "Reset":
 0263                                DCL.Environment.i.world.sceneController.UnloadAllScenesQueued();
 0264                                break;
 265                            case "SetVoiceChatEnabledByScene":
 0266                                if (int.TryParse(msg.payload, out int value)) // The payload should be `string`, this wi
 267                                {
 0268                                    hudControllerGO.SendMessage(msg.type, value);
 269                                }
 0270                                break;
 271                            case "RunPerformanceMeterTool":
 0272                                if (float.TryParse(msg.payload, out float durationInSeconds)) // The payload should be `
 273                                {
 0274                                    mainGO.SendMessage(msg.type, durationInSeconds);
 275                                }
 0276                                break;
 277                            default:
 0278                                if (!messageTypeToBridgeName.TryGetValue(msg.type, out string bridgeName))
 279                                {
 0280                                    bridgeName = "Bridges"; // Default bridge
 281                                }
 282
 0283                                if (bridgeGameObjects.TryGetValue(bridgeName, out GameObject bridgeObject) == false)
 284                                {
 0285                                    bridgeObject = GameObject.Find(bridgeName);
 0286                                    bridgeGameObjects.Add(bridgeName, bridgeObject);
 287                                }
 288
 0289                                if (bridgeObject != null)
 290                                {
 0291                                    bridgeObject.SendMessage(msg.type, msg.payload);
 292                                }
 293                                break;
 294                        }
 295
 0296                        if (DCLWebSocketService.VERBOSE)
 297                        {
 0298                            Debug.Log(
 299                                "<b><color=#0000FF>WebSocketCommunication</color></b> >>> Got it! passing message of typ
 300                                msg.type);
 301                        }
 302                    }
 303                }
 0304            }
 0305            yield return null;
 306        }
 0307    }
 308}