WebSocket sending fails unless I use InvokeRepeating - unity3d

I've implemented a socket connection module according to the instructions here
https://github.com/endel/NativeWebSocket
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using NativeWebSocket;
public class Connection : MonoBehaviour
{
WebSocket websocket;
public bool SpamSend;
public float spamEvery = 3f;
public string uri = "ws://localhost:2567";
[TextArea] public string message;
private string CurrectData;
// Start is called before the first frame update
async void Start()
{
CurrectData = message;
websocket = new WebSocket(uri);
InitilizeWebSocket();
}
async void InitilizeWebSocket()
{
websocket.OnOpen += () =>
{
Debug.Log("Connection open!");
};
websocket.OnError += (e) =>
{
Debug.Log("Error! " + e);
};
websocket.OnClose += (e) =>
{
Debug.Log("Connection closed!");
};
websocket.OnMessage += (bytes) =>
{
Debug.Log("OnMessage!");
//Debug.Log(bytes);
// getting the message as a string
var message = System.Text.Encoding.UTF8.GetString(bytes);
Debug.Log("OnMessage! " + message);
};
if(SpamSend)
// Keep sending messages at every 0.3s
InvokeRepeating("SendWebSocketMessage", 0.0f, spamEvery);
// waiting for messages
await websocket.Connect();
}
void Update()
{
#if !UNITY_WEBGL || UNITY_EDITOR
websocket.DispatchMessageQueue();
#endif
}
async void SendWebSocketMessage()
{
if (websocket.State == WebSocketState.Open)
{
// Sending bytes
// await websocket.Send(new byte[] { 10, 20, 30 });
// Sending plain text
await websocket.SendText(CurrectData);
CancelInvoke("SendWebSocketMessage");
}
}
private async void OnApplicationQuit()
{
await websocket.Close();
}
}
you may now notice the oddity of "invokeRepeating" and CancelInvoke.
this is where I've encountered a problem.
when I tried to just Invoke, I received no response from the server as if it was never sent.
nor when I tried a coroutine - with or without waitForSeconds.
nor when I simply tried SendWebSocketMessage().
What did I miss that only the invokeRepeating made it through?

Related

How would I get a Texture in the project and send it over to discord using a webhook? Unity

What I am trying to do is take a texture(any texture) from unity and use a webhook from discord to send it to discord.
This is what I have so far keep in mind I started coding not long ago so I'm not very familiar with this;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class SendMessage : MonoBehaviour
{
public string Message, Subject;
public string webhook;
public Texture2D screenshot;
// Start is called before the first frame update
void Start()
{
}
IEnumerator SendWebHook(string link, string message, System.Action<bool> action)
{
WWWForm form = new WWWForm();
form.AddField("content", message + screenshot.EncodeToPNG());
using (UnityWebRequest www = UnityWebRequest.Post(link, form))
{
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
action(false);
}
else
{
action(true);
}
}
}
public void send()
{
StartCoroutine(SendWebHook(webhook, Subject + Message, (success) =>
{
if(success)
{
Debug.Log("good");
}
}));
}
}

Read Events from EventHub in Unity3D and HoloLens

We are trying to show events from an Azure EventHub in our HoloLens application. When we run our project in Unity 3D, it works and paint the data from the events.
But when we deploy the same solution on the HoloLens, we don't receive events and also we don't receive any error.
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Microsoft.MixedReality.Toolkit.UI;
using TMPro;
using System;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Azure.Messaging.EventHubs;
using Azure.Messaging.EventHubs.Processor;
using Azure.Storage.Blobs;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Microsoft.MixedReality.Toolkit.Examples.Demos
{
[AddComponentMenu("Scripts/MRTK/Examples/SliderLunarLander")]
public class Manager : MonoBehaviour
{
[SerializeField]
public Animator helice2;
public TextMeshPro textovelocidad;
public EventProcessorClient processor;
public BlobContainerClient storageClient;
private const string storageConnectionString = "XXXX";
private const string blobContainerName = "XXXX";
private const string eventHubsConnectionString = "XXXX";
private const string consumerGroup = "hololens";
private const string EventHubName = "XXXX";
private float? speedValue;
private string errorText = string.Empty;
private CancellationToken cancellationToken;
async void Start()
{
errorText = "Init EventReader...";
storageClient = new BlobContainerClient(storageConnectionString, blobContainerName);
var clientOptions = new EventProcessorClientOptions()
{
ConnectionOptions = new EventHubConnectionOptions ()
{
TransportType = EventHubsTransportType.AmqpWebSockets
}
};
processor = new EventProcessorClient
(
storageClient,
consumerGroup,
eventHubsConnectionString,
clientOptions
);
processor.ProcessEventAsync += processEventHandler;
processor.ProcessErrorAsync += processErrorHandler;
errorText = "Start EventReader...";
await processor.StartProcessingAsync();
try
{
//The processor performs its work in the background; block until cancellation
//to allow processing to take place.
errorText = "Infinite Loop...";
await Task.Delay(Timeout.Infinite);
}
catch (TaskCanceledException tcex)
{
//This is expected when the delay is canceled.
textoError.text = tcex.Message;
}
//Debug.Log("Device client initialited...");
}
public void OnSliderUpdated(SliderEventData eventData)
{
helice2.speed = eventData.NewValue;
}
async void OnDestroy()
{
try
{
await processor.StopProcessingAsync();
}
finally
{
//To prevent leaks, the handlers should be removed when processing is complete.
processor.ProcessEventAsync -= processEventHandler;
processor.ProcessErrorAsync -= processErrorHandler;
}
}
private void Update()
{
if (speedValue != null)
{
helice2.speed = float.Parse(speedValue.ToString());
}
textovelocidad.text = (helice2.speed).ToString("F2") + " r.p.m.";
textovelocidad.text += " | " + infoText;
textoError.text = errorText;
}
async Task processEventHandler(ProcessEventArgs eventArgs)
{
try
{
// Write the body of the event to the console window
//Console.WriteLine("\tRecevied event: {0}", Encoding.UTF8.GetString(eventArgs.Data.Body.ToArray()));
infoText = " Event Received ";
string json = Encoding.UTF8.GetString(eventArgs.Data.Body.ToArray());
var deviceTurbine = JsonSerializer.Deserialize<DeviceTurbine>(json);
if (deviceTurbine != null)
{
speedValue = deviceTurbine.speed;
}
// Update checkpoint in the blob storage so that the app receives only new events the next time it's run
await eventArgs.UpdateCheckpointAsync(eventArgs.CancellationToken);
}
catch (Exception ex)
{
// Handle the exception from handler code
// Debug.LogError(ex.Message);
errorText = ex.Message;
}
}
Task processErrorHandler(ProcessErrorEventArgs eventArgs)
{
try
{
// Write details about the error to the console window
//Console.WriteLine($"\tPartition '{ eventArgs.PartitionId}': an unhandled exception was encountered. This was not expected to happen.");
//Console.WriteLine(eventArgs.Exception.Message);
errorText = eventArgs.Exception.Message;
}
catch
{
// Handle the exception from handler code
errorText = eventArgs.Exception.Message;
}
return Task.CompletedTask;
}
}
class DeviceTurbine
{
private float _speed;
private DateTime _timestamp;
private string _deviceId;
public float speed
{
get; set;
}
public DateTime timestamp
{
get;set;
}
public string deviceId
{
get; set;
}
}
}

Unity How to StartCoroutine OnApplicationQuit?

I want to fire StartCoroutine(LogOutUser(url, () => { Debug.Log("logOut req done"); }));, which sends data to server ,on OnApplicationQuit function . however it gives this error *
NullReferenceException: Object reference not set to an instance of an object
RegisterLogIn+d__16.MoveNext () (at Assets/Scripts/RegisterLogIn.cs:71)*
RegisterLogIn is class of code below
void LogOut()
{
string url = String.Format("http://localhost:7989/RegisterApi/logout?myTempID={0}", myTempID);
StartCoroutine(LogOutUser(url, () => { Debug.Log("logOut req done"); }));
}
private async void OnApplicationQuit()
{
LogOut();
await websocket.Close();
}
IEnumerator LogOutUser(string url, Action onSuccess)
{
UnityWebRequest req = UnityWebRequest.Get(url);
yield return req.SendWebRequest();
while (!req.isDone)
yield return null;
string result = req.downloadHandler.text;
onSuccess();
}
how can i do this ?
I understand OnApplicationQuit not wait for coroutines because is like another thread and continue with their job.
You can wrapper your own application quit to handle your logout.
public class MyGame : MonoBehaviour
{
public void GameLogic()
{
MyApplication.QuitWithLogOut();
}
}
public class MyApplication : Application
{
public static void QuitWithLogOut()
{
Quiter quiter = new GameObject().AddComponent<Quiter>();
quiter.Quit();
}
}
public class Quiter : MonoBehaviour
{
private bool isLogOutDone;
public void Quit()
{
string url = String.Format("http://localhost:7989/RegisterApi/logout?myTempID={0}", myTempID);
StartCoroutine(LogOutUser(url, () => { Debug.Log("logOut req done"); }));
}
LogOutUser(string url, Action onSuccess)
{
UnityWebRequest req = UnityWebRequest.Get(url);
yield return req.SendWebRequest();
while (!req.isDone)
yield return null;
string result = req.downloadHandler.text;
isLogOutDone = true;
onSuccess();
}
}
If you start a coroutine in OnApplicationQuit.. the application will quit before the coroutine has a chance to finish, and all objects are being destroyed.
According to this thread a simple Get SendWebRequest is threaded with no dependency on the main thread, so it should be safe to block the main thread until complete.
https://forum.unity.com/threads/http-requests-without-coroutines.495418/
You can try blocking the main thread from returning and wait for your network request, but I think you only have a few seconds before unity will hard terminate in that case.
Try this:
void LogOut()
{
string url = String.Format("http://localhost:7989/RegisterApi/logout?myTempID={0}", myTempID);
LogOutUser(url, () => { Debug.Log("logOut req done"); });
}
private async void OnApplicationQuit()
{
LogOut();
await websocket.Close();
}
void LogOutUser(string url, Action onSuccess)
{
UnityWebRequest req = UnityWebRequest.Get(url);
req.SendWebRequest();
while (!req.isDone) {
System.Threading.Thread.Sleep(100);
}
string result = req.downloadHandler.text;
onSuccess();
}

Unity 3D Communication between 2 editors

I am trying to stream some data between 2 editors using a simple tcp client/server setup:
Server:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class TCPTestServer : MonoBehaviour {
#region private members
/// <summary>
/// TCPListener to listen for incomming TCP connection
/// requests.
/// </summary>
private TcpListener tcpListener;
/// <summary>
/// Background thread for TcpServer workload.
/// </summary>
private Thread tcpListenerThread;
/// <summary>
/// Create handle to connected tcp client.
/// </summary>
private TcpClient connectedTcpClient;
#endregion
// Use this for initialization
void Start () {
// Start TcpServer background thread
tcpListenerThread = new Thread (new ThreadStart(ListenForIncommingRequests));
tcpListenerThread.IsBackground = true;
tcpListenerThread.Start();
}
// Update is called once per frame
void Update () {
SendMessage();
}
/// <summary>
/// Runs in background TcpServerThread; Handles incomming TcpClient requests
/// </summary>
private void ListenForIncommingRequests () {
try {
// Create listener on localhost port 8052.
tcpListener = new TcpListener(IPAddress.Parse("myip"), 65535);
tcpListener.Start();
Debug.Log("Server is listening");
Byte[] bytes = new Byte[1024];
while (true) {
using (connectedTcpClient = tcpListener.AcceptTcpClient()) {
// Get a stream object for reading
using (NetworkStream stream = connectedTcpClient.GetStream()) {
int length;
// Read incomming stream into byte arrary.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) {
var incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
// Convert byte array to string message.
string clientMessage = Encoding.ASCII.GetString(incommingData);
Debug.Log("client message received as: " + clientMessage);
}
}
}
}
}
catch (SocketException socketException) {
Debug.Log("SocketException " + socketException.ToString());
}
}
/// <summary>
/// Send message to client using socket connection.
/// </summary>
private void SendMessage() {
if (connectedTcpClient == null) {
return;
}
try {
// Get a stream object for writing.
NetworkStream stream = connectedTcpClient.GetStream();
if (stream.CanWrite) {
string serverMessage = this.gameObject.transform.position.ToString();
// Convert string message to byte array.
byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(serverMessage);
// Write byte array to socketConnection stream.
stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
Debug.Log("Server sent his message - should be received by client");
}
}
catch (SocketException socketException) {
Debug.Log("Socket exception: " + socketException);
}
}
void OnApplicationQuit()
{
tcpListenerThread.Abort();
connectedTcpClient.Close ();
}
}
Client:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class TCPTestClient : MonoBehaviour {
#region private members
private TcpClient socketConnection;
private Thread clientReceiveThread;
#endregion
// Use this for initialization
void Start () {
ConnectToTcpServer();
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Space)) {
SendMessage();
}
}
/// <summary>
/// Setup socket connection.
/// </summary>
private void ConnectToTcpServer () {
try {
clientReceiveThread = new Thread (new ThreadStart(ListenForData));
clientReceiveThread.IsBackground = true;
clientReceiveThread.Start();
}
catch (Exception e) {
Debug.Log("On client connect exception " + e);
}
}
/// <summary>
/// Runs in background clientReceiveThread; Listens for incomming data.
/// </summary>
private void ListenForData() {
try {
socketConnection = new TcpClient("myip", 65535);
Byte[] bytes = new Byte[1024];
while (true) {
// Get a stream object for reading
using (NetworkStream stream = socketConnection.GetStream()) {
int length;
// Read incomming stream into byte arrary.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) {
var incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
// Convert byte array to string message.
string serverMessage = Encoding.ASCII.GetString(incommingData);
Debug.Log("server message received as: " + serverMessage);
}
}
}
}
catch (SocketException socketException) {
Debug.Log("Socket exception: " + socketException);
}
}
/// <summary>
/// Send message to server using socket connection.
/// </summary>
private void SendMessage() {
if (socketConnection == null) {
return;
}
try {
// Get a stream object for writing.
NetworkStream stream = socketConnection.GetStream();
if (stream.CanWrite) {
string clientMessage = "This is a message from one of your clients.";
// Convert string message to byte array.
byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(clientMessage);
// Write byte array to socketConnection stream.
stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
//Debug.Log("Client sent his message - should be received by server");
}
}
catch (SocketException socketException) {
Debug.Log("Socket exception: " + socketException);
}
}
void OnApplicationQuit()
{
clientReceiveThread.Abort();
socketConnection.Close ();
}
}
This works in local but wont work if i run the server and client seperately in two different computers. Moreover, i triend ping.eu and my port seems closed even if i forwarded from my firewall settings. What am I doing wrong?

C# Server Load balancer works only when break-point is set in VS debugger?

The Load balancer accepts incoming requests, re-sends them to multiple servers, and returns the answers from the servers to the awaiting clients.
// Dispatcher.cs
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace LoadBallancer {
public class Dispatcher
{
// set the TcpListener on port 8890
int port = 8890;
TcpListener server;
List<CoreComm> processors = new List<CoreComm>();
static void Main()
{
var dispatcher = new Dispatcher();
dispatcher.ListenForRequests();
}
public Dispatcher()
{
server = new TcpListener(IPAddress.Any, port);
}
public void ListenForRequests()
{
server.Start();
while (true)
{
try
{
// Start listening for client requests
// Enter the listening loop
Console.Write("Waiting for a connection... ");
lock(server)
{
// Perform a blocking call to accept requests.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected.");
ThreadPool.QueueUserWorkItem(ThreadProc, client);
}
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e);
}
}
}
private static void ThreadProc(object obj)
{
var processor = new CoreComm((TcpClient)obj);
processor.ReSendRequest(null);
}
}
}
// CoreComm.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Configuration;
using System.Threading;
namespace LoadBallancer
{
public class IamServer
{
public string Url { get; set; }
public int Port { get; set; }
public string Type { get; set; }
}
public class CoreComm
{
// Buffer for reading data
int bufSize = 1024;
static List<IamServer> servers = new List<IamServer>();
protected TcpClient acceptorSocket;
NetworkStream acceptorStream;
protected TcpClient clientSocket;
protected List<KeyValuePair<int, byte[]>> requestPackets = new List<KeyValuePair<int, byte[]>>();
static CoreComm()
{
// reading config for servers' parameters
}
public CoreComm(TcpClient socket)
{
acceptorSocket = socket;
// Get a stream object for reading and writing
acceptorStream = acceptorSocket.GetStream();
}
private void ReadFromAcceptorStream()
{
// Loop to receive all the data sent by the client.
while (acceptorStream.DataAvailable)
{
byte[] requestBuffer = new byte[bufSize];
int i = acceptorStream.Read(requestBuffer, 0, requestBuffer.Length);
requestPackets.Add(new KeyValuePair<int, byte[]>(i, requestBuffer));
}
}
public void ReSendRequest(Object threadContext)
{
ReadFromAcceptorStream();
var servers = GetDestinationServers(null);
if (servers.Count == 0)
acceptorStream.Write(ErrMessage, 0, ErrMessage.Length);
else
// for debug only send the first in the list
SendRequestToServer(servers[0]);
// Shutdown and end connection
acceptorSocket.Close();
}
public void SendRequestToServer(IamServer server)
{
clientSocket = new TcpClient();
clientSocket.Connect(server.Url, server.Port);
NetworkStream clientStream = clientSocket.GetStream();
foreach (var packet in requestPackets)
clientStream.Write(packet.Value, 0, packet.Key);
var requestBuffer = new byte[bufSize];
while (clientStream.DataAvailable)
{
int i = clientStream.Read(requestBuffer, 0, requestBuffer.Length);
acceptorStream.Write(requestBuffer, 0, i);
}
clientSocket.Close();
}
// Mock up of the real load balancing algorithm
static int lastServerAnswered = 0;
public List<IamServer> GetDestinationServers(string requestData)
{
// processing to determine the query destinations
lock(servers)
{
// patch
int currentServerNum = lastServerAnswered;
lastServerAnswered ++ ;
if (lastServerAnswered > servers.Count - 1)
lastServerAnswered = 0;
return new List<IamServer> { servers[currentServerNum] };
}
}
}
}
So it works right when I set break-point in the code and does not work otherwise.
Any ideas?
The problem was found to be in the code:
while (clientStream.DataAvailable)
{
int i = clientStream.Read(requestBuffer, 0, requestBuffer.Length);
acceptorStream.Write(requestBuffer, 0, i);
}
Actually it happened that for some packets clientStream.DataAvailable was false even if there was still remaining data to be received. The solution is based on the application level protocol for which the Load Balancer had been developed that sends in the first 4 bytes of the stream the number of the total bytes that are sent.The code becomes as follows:
var responseBuffer = new byte[bufSize];
int numTotalBytesStreamed = clientStream.Read(responseBuffer, 0, responseBuffer.Length);
int numBytesToStream = GetNumBytesInTheStream(responseBuffer);
acceptorStream.Write(responseBuffer, 0, numTotalBytesStreamed);
while (numBytesToStream > numTotalBytesStreamed)
{
while (!clientStream.DataAvailable)
Thread.Sleep(1);
int numMoreBytesStreamed = clientStream.Read(responseBuffer, 0, responseBuffer.Length);
acceptorStream.Write(responseBuffer, 0, numMoreBytesStreamed);
numTotalBytesStreamed += numMoreBytesStreamed;
}
acceptorStream.Flush();
clientSocket.Close();
The solution works and is extremely stable for continuous loads of hundreds of requests per second.