/// <summary> /// Internal helper to wrap a coroutine into a synchronous call /// for use inside a <see cref="Task"/> object. /// </summary> /// <param name="msg">the message to send</param> private IEnumerator PostToServerAndWait(SignalerMessage message, ManualResetEvent mre) { // Start the coroutine and wait for it to finish yield return(StartCoroutine(PostToServer(message))); mre.Set(); }
/// <inheritdoc/> public override Task SendMessageAsync(SignalerMessage message) { // This method needs to return a Task object which gets completed once the signaler message // has been sent. Because the implementation uses a Unity coroutine, use a reset event to // signal the task to complete from the coroutine after the message is sent. // Note that the coroutine is a Unity object so needs to be started from the main Unity thread. var mre = new ManualResetEvent(false); _mainThreadWorkQueue.Enqueue(() => StartCoroutine(PostToServerAndWait(message, mre))); return(Task.Run(() => mre.WaitOne())); }
/// <summary> /// Internal helper for sending HTTP data to the node-dss server using POST /// </summary> /// <param name="msg">the message to send</param> private IEnumerator PostToServer(SignalerMessage msg) { var data = System.Text.Encoding.UTF8.GetBytes(JsonUtility.ToJson(msg)); var www = new UnityWebRequest($"{HttpServerAddress}data/{RemotePeerId}", UnityWebRequest.kHttpVerbPOST); www.uploadHandler = new UploadHandlerRaw(data); yield return(www.SendWebRequest()); if (AutoLogErrors && (www.isNetworkError || www.isHttpError)) { Debug.Log("Failure sending message: " + www.error); } }
/// <summary> /// Send a message to the signaling server to be dispatched to the remote /// endpoint specified by <see cref="SignalerMessage.TargetId"/>. /// </summary> /// <param name="message">Message to send</param> public Task SendMessageAsync(SignalerMessage message) { if (string.IsNullOrWhiteSpace(_httpServerAddress)) { throw new ArgumentException("Invalid empty HTTP server address."); } // Send a POST request to the server with the JSON-serialized message. var jsonMsg = JsonConvert.SerializeObject(message); string requestUri = $"{_httpServerAddress}data/{RemotePeerId}"; HttpContent content = new StringContent(jsonMsg); var task = _httpClient.PostAsync(requestUri, content).ContinueWith((postTask) => { if (postTask.Exception != null) { OnFailure?.Invoke(postTask.Exception); } }); // Atomic read if (Interlocked.CompareExchange(ref _connectedEventFired, 1, 1) == 1) { return(task); } // On first successful message, fire the OnConnect event return(task.ContinueWith((prevTask) => { if (prevTask.Exception != null) { OnFailure?.Invoke(prevTask.Exception); } if (prevTask.IsCompletedSuccessfully) { // Only invoke if this task was the first one to change the value, because // another task may have completed faster in the meantime and already invoked. if (0 == Interlocked.Exchange(ref _connectedEventFired, 1)) { OnConnect?.Invoke(); } } })); }
/// <summary> /// Asynchronously send a signaling message to the remote peer. /// </summary> /// <param name="message">The signaling message to send to the remote peer.</param> /// <returns> /// A <see cref="Task"/> object completed once the message has been sent, /// but not necessarily delivered. /// </returns> public abstract Task SendMessageAsync(SignalerMessage message);