< 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:186
Coverable lines:187
Total lines:314
Line coverage:0.5% (1 of 187)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
WebSocketCommunication()0%110100%
WebSocketCommunication(...)0%2100%
Dispose()0%2100%
StartServer(...)0%90900%
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.Sockets;
 5using DCL;
 6using UnityEngine;
 7using WebSocketSharp;
 8using WebSocketSharp.Server;
 9
 10public class WebSocketCommunication : IKernelCommunication
 11{
 12    public static DCLWebSocketService service;
 13
 14    [System.NonSerialized]
 115    public static Queue<DCLWebSocketService.Message> queuedMessages = new Queue<DCLWebSocketService.Message>();
 16
 17    [System.NonSerialized]
 18    public static volatile bool queuedMessagesDirty;
 19
 020    private Dictionary<string, GameObject> bridgeGameObjects = new Dictionary<string, GameObject>();
 21
 022    public Dictionary<string, string> messageTypeToBridgeName = new Dictionary<string, string>(); // Public to be able t
 23    private bool requestStop = false;
 24    private Coroutine updateCoroutine;
 25
 26    WebSocketServer ws;
 27
 028    public WebSocketCommunication(bool withSSL = false, int startPort = 7666, int endPort = 7800)
 29    {
 030        InitMessageTypeToBridgeName();
 31
 032        DCL.DataStore.i.debugConfig.isWssDebugMode = true;
 33
 034        string url = StartServer(startPort, endPort, withSSL);
 35
 036        Debug.Log("WebSocket Server URL: " + url);
 37
 038        DataStore.i.wsCommunication.url = url;
 39
 040        DataStore.i.wsCommunication.communicationReady.Set(true);
 41
 042        updateCoroutine = CoroutineStarter.Start(ProcessMessages());
 043    }
 44
 045    public bool isServerReady => ws.IsListening;
 046    public void Dispose() { ws.Stop(); }
 47    public static event Action<DCLWebSocketService> OnWebSocketServiceAdded;
 48
 49    private string StartServer(int port, int maxPort, bool withSSL, bool verbose = false)
 50    {
 051        if (port > maxPort)
 52        {
 053            throw new SocketException((int)SocketError.AddressAlreadyInUse);
 54        }
 55        string wssServerUrl;
 056        string wssServiceId = "dcl";
 57        try
 58        {
 059            if (withSSL)
 60            {
 061                wssServerUrl = $"wss://localhost:{port}/";
 062                ws = new WebSocketServer(wssServerUrl)
 63                {
 64                    SslConfiguration =
 65                    {
 66                        ServerCertificate = CertificateUtils.CreateSelfSignedCert(),
 67                        ClientCertificateRequired = false,
 68                        CheckCertificateRevocation = false,
 069                        ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true,
 70                        EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12
 71                    },
 72                    KeepClean = false
 73                };
 74            }
 75            else
 76            {
 077                wssServerUrl = $"ws://localhost:{port}/";
 078                ws = new WebSocketServer(wssServerUrl);
 79            }
 80
 081            ws.AddWebSocketService("/" + wssServiceId, () =>
 82            {
 083                service = new DCLWebSocketService();
 084                OnWebSocketServiceAdded?.Invoke(service);
 085                return service;
 86            });
 87
 088            if (verbose)
 89            {
 090                ws.Log.Level = LogLevel.Debug;
 091                ws.Log.Output += OnWebSocketLog;
 92            }
 093            ws.Start();
 094        }
 095        catch (InvalidOperationException e)
 96        {
 097            ws.Stop();
 098            if (withSSL) // Search for available ports only if we're using SSL
 99            {
 0100                SocketException se = (SocketException)e.InnerException;
 0101                if (se is { SocketErrorCode: SocketError.AddressAlreadyInUse })
 102                {
 0103                    return StartServer(port + 1, maxPort, withSSL);
 104                }
 105            }
 0106            throw new InvalidOperationException(e.Message, e.InnerException);
 107        }
 108
 0109        string wssUrl = wssServerUrl + wssServiceId;
 0110        return wssUrl;
 0111    }
 112    private void OnWebSocketLog(LogData logData, string message)
 113    {
 0114        switch (logData.Level)
 115        {
 116            case LogLevel.Debug:
 0117                Debug.Log($"[WebSocket] {logData.Message}");
 0118                break;
 119            case LogLevel.Warn:
 0120                Debug.LogWarning($"[WebSocket] {logData.Message}");
 0121                break;
 122            case LogLevel.Error:
 0123                Debug.LogError($"[WebSocket] {logData.Message}");
 0124                break;
 125            case LogLevel.Fatal:
 0126                Debug.LogError($"[WebSocket] {logData.Message}");
 127                break;
 128        }
 0129    }
 130
 131    private void InitMessageTypeToBridgeName()
 132    {
 133        // Please, use `Bridges` as a bridge name, avoid adding messages here. The system will use `Bridges` as the defa
 0134        messageTypeToBridgeName["SetDebug"] = "Main";
 0135        messageTypeToBridgeName["SetSceneDebugPanel"] = "Main";
 0136        messageTypeToBridgeName["SetMemoryUsage"] = "Main";
 0137        messageTypeToBridgeName["ShowFPSPanel"] = "Main";
 0138        messageTypeToBridgeName["HideFPSPanel"] = "Main";
 0139        messageTypeToBridgeName["SetEngineDebugPanel"] = "Main";
 0140        messageTypeToBridgeName["SendSceneMessage"] = "Main";
 0141        messageTypeToBridgeName["LoadParcelScenes"] = "Main";
 0142        messageTypeToBridgeName["UnloadScene"] = "Main";
 0143        messageTypeToBridgeName["UnloadSceneV2"] = "Main";
 0144        messageTypeToBridgeName["Reset"] = "Main";
 0145        messageTypeToBridgeName["CreateGlobalScene"] = "Main";
 0146        messageTypeToBridgeName["BuilderReady"] = "Main";
 0147        messageTypeToBridgeName["UpdateParcelScenes"] = "Main";
 0148        messageTypeToBridgeName["LoadProfile"] = "Main";
 0149        messageTypeToBridgeName["AddUserProfileToCatalog"] = "Main";
 0150        messageTypeToBridgeName["AddUserProfilesToCatalog"] = "Main";
 0151        messageTypeToBridgeName["RemoveUserProfilesFromCatalog"] = "Main";
 0152        messageTypeToBridgeName["ActivateRendering"] = "Main";
 0153        messageTypeToBridgeName["DeactivateRendering"] = "Main";
 0154        messageTypeToBridgeName["ForceActivateRendering"] = "Main";
 0155        messageTypeToBridgeName["AddWearablesToCatalog"] = "Main";
 0156        messageTypeToBridgeName["WearablesRequestFailed"] = "Main";
 0157        messageTypeToBridgeName["RemoveWearablesFromCatalog"] = "Main";
 0158        messageTypeToBridgeName["ClearWearableCatalog"] = "Main";
 0159        messageTypeToBridgeName["InitializeFriends"] = "Main";
 0160        messageTypeToBridgeName["UpdateFriendshipStatus"] = "Main";
 0161        messageTypeToBridgeName["UpdateUserPresence"] = "Main";
 0162        messageTypeToBridgeName["FriendNotFound"] = "Main";
 0163        messageTypeToBridgeName["AddMessageToChatWindow"] = "Main";
 0164        messageTypeToBridgeName["UpdateMinimapSceneInformation"] = "Main";
 0165        messageTypeToBridgeName["UpdateHotScenesList"] = "Main";
 0166        messageTypeToBridgeName["SetRenderProfile"] = "Main";
 0167        messageTypeToBridgeName["CrashPayloadRequest"] = "Main";
 0168        messageTypeToBridgeName["SetDisableAssetBundles"] = "Main";
 0169        messageTypeToBridgeName["DumpRendererLockersInfo"] = "Main";
 0170        messageTypeToBridgeName["PublishSceneResult"] = "Main";
 0171        messageTypeToBridgeName["BuilderProjectInfo"] = "Main";
 0172        messageTypeToBridgeName["BuilderInWorldCatalogHeaders"] = "Main";
 0173        messageTypeToBridgeName["RequestedHeaders"] = "Main";
 0174        messageTypeToBridgeName["AddAssets"] = "Main";
 0175        messageTypeToBridgeName["RunPerformanceMeterTool"] = "Main";
 0176        messageTypeToBridgeName["InstantiateBotsAtWorldPos"] = "Main";
 0177        messageTypeToBridgeName["InstantiateBotsAtCoords"] = "Main";
 0178        messageTypeToBridgeName["StartBotsRandomizedMovement"] = "Main";
 0179        messageTypeToBridgeName["StopBotsMovement"] = "Main";
 0180        messageTypeToBridgeName["RemoveBot"] = "Main";
 0181        messageTypeToBridgeName["ClearBots"] = "Main";
 0182        messageTypeToBridgeName["ToggleSceneBoundingBoxes"] = "Main";
 0183        messageTypeToBridgeName["TogglePreviewMenu"] = "Main";
 0184        messageTypeToBridgeName["ToggleSceneSpawnPoints"] = "Main";
 0185        messageTypeToBridgeName["AddFriendsWithDirectMessages"] = "Main";
 0186        messageTypeToBridgeName["AddFriends"] = "Main";
 0187        messageTypeToBridgeName["AddFriendRequests"] = "Main";
 0188        messageTypeToBridgeName["UpdateTotalUnseenMessagesByUser"] = "Main";
 0189        messageTypeToBridgeName["UpdateTotalFriendRequests"] = "Main";
 0190        messageTypeToBridgeName["UpdateTotalFriends"] = "Main";
 0191        messageTypeToBridgeName["InitializeChat"] = "Main";
 0192        messageTypeToBridgeName["AddChatMessages"] = "Main";
 0193        messageTypeToBridgeName["UpdateUserUnseenMessages"] = "Main";
 0194        messageTypeToBridgeName["UpdateTotalUnseenMessages"] = "Main";
 0195        messageTypeToBridgeName["UpdateChannelInfo"] = "Main";
 0196        messageTypeToBridgeName["JoinChannelConfirmation"] = "Main";
 0197        messageTypeToBridgeName["JoinChannelError"] = "Main";
 0198        messageTypeToBridgeName["LeaveChannelError"] = "Main";
 0199        messageTypeToBridgeName["MuteChannelError"] = "Main";
 0200        messageTypeToBridgeName["UpdateTotalUnseenMessagesByChannel"] = "Main";
 0201        messageTypeToBridgeName["UpdateChannelMembers"] = "Main";
 0202        messageTypeToBridgeName["UpdateHomeScene"] = "Main";
 0203        messageTypeToBridgeName["UpdateChannelSearchResults"] = "Main";
 204
 0205        messageTypeToBridgeName["Teleport"] = "CharacterController";
 206
 0207        messageTypeToBridgeName["SetRotation"] = "CameraController";
 208
 0209        messageTypeToBridgeName["ShowNotificationFromJson"] = "HUDController";
 0210        messageTypeToBridgeName["ConfigureHUDElement"] = "HUDController";
 0211        messageTypeToBridgeName["ShowTermsOfServices"] = "HUDController";
 0212        messageTypeToBridgeName["RequestTeleport"] = "HUDController";
 0213        messageTypeToBridgeName["ShowAvatarEditorInSignUp"] = "HUDController";
 0214        messageTypeToBridgeName["SetUserTalking"] = "HUDController";
 0215        messageTypeToBridgeName["SetUsersMuted"] = "HUDController";
 0216        messageTypeToBridgeName["ShowWelcomeNotification"] = "HUDController";
 0217        messageTypeToBridgeName["UpdateBalanceOfMANA"] = "HUDController";
 0218        messageTypeToBridgeName["SetPlayerTalking"] = "HUDController";
 0219        messageTypeToBridgeName["SetVoiceChatEnabledByScene"] = "HUDController";
 0220        messageTypeToBridgeName["TriggerSelfUserExpression"] = "HUDController";
 0221        messageTypeToBridgeName["AirdroppingRequest"] = "HUDController";
 222
 0223        messageTypeToBridgeName["GetMousePosition"] = "BuilderController";
 0224        messageTypeToBridgeName["SelectGizmo"] = "BuilderController";
 0225        messageTypeToBridgeName["ResetObject"] = "BuilderController";
 0226        messageTypeToBridgeName["ZoomDelta"] = "BuilderController";
 0227        messageTypeToBridgeName["SetPlayMode"] = "BuilderController";
 0228        messageTypeToBridgeName["TakeScreenshot"] = "BuilderController";
 0229        messageTypeToBridgeName["ResetBuilderScene"] = "BuilderController";
 0230        messageTypeToBridgeName["SetBuilderCameraPosition"] = "BuilderController";
 0231        messageTypeToBridgeName["SetBuilderCameraRotation"] = "BuilderController";
 0232        messageTypeToBridgeName["ResetBuilderCameraZoom"] = "BuilderController";
 0233        messageTypeToBridgeName["SetGridResolution"] = "BuilderController";
 0234        messageTypeToBridgeName["OnBuilderKeyDown"] = "BuilderController";
 0235        messageTypeToBridgeName["UnloadBuilderScene"] = "BuilderController";
 0236        messageTypeToBridgeName["SetSelectedEntities"] = "BuilderController";
 0237        messageTypeToBridgeName["GetCameraTargetBuilder"] = "BuilderController";
 0238        messageTypeToBridgeName["PreloadFile"] = "BuilderController";
 0239        messageTypeToBridgeName["SetBuilderConfiguration"] = "BuilderController";
 240
 0241        messageTypeToBridgeName["SetTutorialEnabled"] = "TutorialController";
 0242        messageTypeToBridgeName["SetTutorialEnabledForUsersThatAlreadyDidTheTutorial"] = "TutorialController";
 243
 0244        messageTypeToBridgeName["VoiceChatStatus"] = "VoiceChatController";
 0245    }
 246
 247    IEnumerator ProcessMessages()
 248    {
 0249        var hudControllerGO = GameObject.Find("HUDController");
 0250        var mainGO = GameObject.Find("Main");
 251
 0252        while (!requestStop)
 253        {
 0254            lock (queuedMessages)
 255            {
 0256                if (queuedMessagesDirty)
 257                {
 0258                    while (queuedMessages.Count > 0)
 259                    {
 0260                        DCLWebSocketService.Message msg = queuedMessages.Dequeue();
 261
 0262                        switch (msg.type)
 263                        {
 264                            // Add to this list the messages that are used a lot and you want better performance
 265                            case "SendSceneMessage":
 0266                                DCL.Environment.i.world.sceneController.SendSceneMessage(msg.payload);
 0267                                break;
 268                            case "Reset":
 0269                                DCL.Environment.i.world.sceneController.UnloadAllScenesQueued();
 0270                                break;
 271                            case "SetVoiceChatEnabledByScene":
 0272                                if (int.TryParse(msg.payload, out int value)) // The payload should be `string`, this wi
 273                                {
 0274                                    hudControllerGO.SendMessage(msg.type, value);
 275                                }
 0276                                break;
 277                            case "RunPerformanceMeterTool":
 0278                                if (float.TryParse(msg.payload, out float durationInSeconds)) // The payload should be `
 279                                {
 0280                                    mainGO.SendMessage(msg.type, durationInSeconds);
 281                                }
 0282                                break;
 283                            default:
 0284                                if (!messageTypeToBridgeName.TryGetValue(msg.type, out string bridgeName))
 285                                {
 0286                                    bridgeName = "Bridges"; // Default bridge
 287                                }
 288
 0289                                if (bridgeGameObjects.TryGetValue(bridgeName, out GameObject bridgeObject) == false)
 290                                {
 0291                                    bridgeObject = GameObject.Find(bridgeName);
 0292                                    bridgeGameObjects.Add(bridgeName, bridgeObject);
 293                                }
 294
 0295                                if (bridgeObject != null)
 296                                {
 0297                                    bridgeObject.SendMessage(msg.type, msg.payload);
 298                                }
 299                                break;
 300                        }
 301
 0302                        if (DCLWebSocketService.VERBOSE)
 303                        {
 0304                            Debug.Log(
 305                                "<b><color=#0000FF>WebSocketCommunication</color></b> >>> Got it! passing message of typ
 306                                msg.type);
 307                        }
 308                    }
 309                }
 0310            }
 0311            yield return null;
 312        }
 0313    }
 314}