How to get server side events (onmessage) in C# in Unity? - c#

Im not experienced at all with SSE (or web development in general) so please forgive my ignorance on display. Im trying to get onmessage events from an SSE stream in C# in Unity. I need this to run continuously (preferably async) as these events just keep coming.
For context I'm trying to get events from: https://www.blaseball.com/events/streamGameData
The behaviour I'm trying to replicate in Javascript is:
const evtSource = new EventSource(https://www.blaseball.com/events/streamGameData, {});
evtSource.onmessage = function(event) {
var data = JSON.parse(event.data)["value"];
// Use data here
}
So far I have tried:
Web Request
I found some sample code on a Github jist that uses WebRequest (code below). This works, and gives me the right data back, but I dont understand how (if at all) I can only get the onmessage events, like the supplied JS, this way. Obviously this code just locks the application in its current state.
void Main()
{
var request = WebRequest.Create(new Uri(url));
var response = request.GetResponse();
var stream = response.GetResponseStream();
var encoder = new UTF8Encoding();
var buffer = new byte[2048];
while(true)
{
if (!stream.CanRead)
return;
int length = stream.Read(buffer, 0, 2048);
if (length > 0)
{
var text = encoder.GetString(buffer, 0, length);
// Parse...
}
}
}
Service Stack
I tried using the ServiceStack ServerEventsClient (Link) to get events. I built the NuGet package in VSCode and placed the .netstandard2.0 builds in Unity's Plugins folder. The packages compile fine in Unity and I can access their APIs with no issue.
However, await client.Connect() never returns. I'll admit that I dont really understand these APIs. I used the code verbatim from the link above using Using C# Async/Await friendly API’s and I also tried with client.Start() for good measure. Nothing. However one line in the ServiceStack documentation suggests that this only works with ServiceStack servers? (I do not know enough about SSE to understand the difference)
async void Connect()
{
var client = new ServerEventsClient("https://www.blaseball.com/events/streamGameData");
client.OnMessage += (evt) =>
{
Debug.Log("Message!");
};
client.Start();
ServerEventConnect connectMsg = await client.Connect();
// Never gets here...
}
Can anyone explain what I'm doing wrong with ServerStack, or if that route is even possible? Or perhaps help with a Web Request method? Recommendations for other methods or libraries are also very welcome...

Related

TwitchLib Help- Work around old TwitchClient() method

I was watching a tutorial on how to script a bot using C# and the instructor used (to my knowledge) an old call to TwitchClient which takes credentials and references. However, it is currently not the case and I'm wondering now what might be a good way to work around it. Currently, the method takes a websocket and logger but I have suspicion that you still need to use credentials and references.
Any help will be appreciated.
Here's the video with the timestamp: https://youtu.be/5f1T9hQqJps?t=8m3s
Instead of the single line in the video, these two lines should now achieve mostly the same effect:
client = new TwitchClient();
client.Initialize(credentials, "channel");
If you want to also enable logging (like in the video), then you will need to provide an instance of ILogger to the first call like so:
client = new TwitchClient(null, myLoggingInstance);
The WebSocket parameter is used for testing (so you can generate your own traffic to test your bot), the docs advise not to set this.
its quite simple actually, even the github page shows a simple example:
ConnectionCredentials credentials = new ConnectionCredentials("twitch_username", "access_token");
var clientOptions = new ClientOptions
{
MessagesAllowedInPeriod = 750,
ThrottlingPeriod = TimeSpan.FromSeconds(30)
};
WebSocketClient customClient = new WebSocketClient(clientOptions);
client = new TwitchClient(customClient);
client.Initialize(credentials, "channel");
client.OnLog += Client_OnLog;
client.Connect();
then later declare this function:
private void Client_OnLog(object sender, OnLogArgs e)
{
Console.WriteLine($"{e.DateTime.ToString()}: {e.BotUsername} - {e.Data}");
}

Continuous Speech Recognition using Microsoft Cognitive Speech + Websocket - Xamarin

I am trying to build a continuous speech recognition from microphone using the Microsoft Cognitive Speech for Xamarin Android. I don't think there is library for Xamarin so I modified the "Xamarin.Cognitive.BingSpeech" library a little bit (the endpoint, etc) to get it work. I have some problem
I want to connect to the microsoft web socket by following tutorial from https://learn.microsoft.com/en-us/azure/cognitive-services/speech/api-reference-rest/websocketprotocol.
I tried sending HTTPREQUEST using basic HttpClient and got the 101 switch protocol result (I guess I succeed this part?).
UPDATE : My HTTP Request is :
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
var request = new HttpWebRequest(uriBuilder.Uri);
request.Headers.Add("Authorization", new System.Net.Http.Headers.AuthenticationHeaderValue(Bearer, AuthClient.Token).ToString());
request.Accept=MimeTypes.Json;
request.Host = SpeechEndpoint.Host;
request.Connection = "Upgrade";
request.Headers.Add("Upgrade", "Websocket");
request.KeepAlive = true;
request.Method = "GET";
request.CookieContainer = new CookieContainer();
request.AllowAutoRedirect = true;
request.Date = DateTime.Now;
request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.CacheIfAvailable);
request.Headers.Add("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==");
request.Headers.Add("Sec-WebSocket-Version", "13");
request.Headers.Add("Sec-WebSocket-Protocol", "chat, superchat");
request.Headers.Add("X-ConnectionId",xConnectionId = Guid.NewGuid().ToString().ToUpper());
After making a HTTPRequest, I am trying to connect to the websocket,
but I always get "Unable to connect to remote server" without any error code or anything. (wss://xxxxxxxx).
Uri wsuri = new Uri(AppConfig.BINGWSSURI);
await _socketclient.ConnectAsync(wsuri, CancellationToken.None);
Log.Info("WSOCKETFINISH", _socketclient.State.ToString());
The second thing I want to achieve is to stream the audio from microphone to the websocket using binary message, so I have to
Record from Microphone (I am using Plugin.AudioRecorder)
Cut it into small chunk pieces
Stream the small pieces asynchronously using the websocket
What I want to achieve : Speech to Text using Microphone with Microsoft Cognitive Speech, dictation mode, so I need partial result instead of waiting the recording to be completed.
I think you want to convert the speech to text. Since the Xamarin.Cognitive.BingSpeech needs you to record the speech and send them as file or stream to the server. I think you could try to use Android speech. And it could also convert text to speech. Here is an example.
If you want to use Xamarin.Cognitive.BingSpeech, you could use Audio Recorder plugin to record the speech and use BingSpeechApiClient to send to server. For example:
BingSpeechApiClient bingSpeechClient = new BingSpeechApiClient ("My Bing Speech API Subscription Key");
var audioFile = "/a/path/to/my/audio/file/in/WAV/format.wav";
var simpleResult = await bingSpeechClient.SpeechToTextSimple (audioFile);
Or
var simpleResult = await bingSpeechClient.SpeechToTextSimple (stream, <sample rate>, <audio record Task>);
Here is the example for Xamarin.Cognitive.BingSpeech.
Update:
I always get "Unable to connect to remote server" without any error code or anything.
You are missing something value in header.
X-ConnectionIdYou need to generate a UUID and add it to the header. For example: client.Options.SetRequestHeader("X-ConnectionId", System.Guid.NewGuid().ToString());
Authorization You need post your subscription key to https://api.cognitive.microsoft.com/sts/v1.0/issueToken. You could use Postman to do this. Then add the return value in the header.
client.Options.SetRequestHeader("Authorization", "eyJ0eXAiOiJKV1Q....uW72PAOBRcUvqY");
so I need partial result instead of waiting the recording to be completed
You could use the GetAudioFileStream() method.For example:
var audioRecordTask = await recorder.StartRecording();
using (var stream = recorder.GetAudioFileStream ())
{
//this will get the recording audio data as it continues to record
}
Update2:
The websoket part code:
var client = new ClientWebSocket();
client.Options.UseDefaultCredentials = true;
client.Options.SetRequestHeader("X-ConnectionId", System.Guid.NewGuid().ToString());
client.Options.SetRequestHeader("Authorization", "eyJ0eXAiOiJKV1QiL....16pbFPOWT3VHXot8");
var a = client.ConnectAsync(new Uri("wss://speech.platform.bing.com/speech/recognition/Dictation/cognitiveservices/v1"), CancellationToken.None);
a.Wait();
Note: Keep your Authorization's value up-to-date.

PHP - Upload specified collection of values to a resource identified by specified URI

Just finished an automatic newsletter-subscriber module written in C#. Now I have to translate it in PHP so I can use it with my wordpress sites as well. I'm not that good in PHP as most of the time I'm writting .NET MVC applications. In C# I came up with the following solution:
// Code below runs each time a user submits the newsletter form
using (var client = new WebClient()) {
var MyValues = new NameValueCollection();
MyValues["list"] = "123456789";
MyValues["boolean"] = "true";
MyValues["name"] = model.NameSec;
MyValues["email"] = model.EmailSec;
var MyResponse = client.UploadValues("http://www.XXXXXX.com/subscribe", MyValues);
var MyValue = Encoding.Default.GetString(MyResponse);
if (MyValue.Equals("true")) {
// All correct
}
else {
// Oops, smth went wrong
}
}
Now I'm looking for a similar method as WebClient.UploadValues but for PHP. Could you please give me some guidance?
WebClient.UploadValues() is making a POST request to your URI. To achieve the same in PHP, you should look into Curl. There are plenty of examples available and a number of questions that already address the topic.
This is probably the best answer with source code/examples.

Upload Image to Twitter

I am trying to upload an image to Twitter using Twitter API Version 1.1 and the update_with_media.json method.
https://dev.twitter.com/docs/api/1.1/post/statuses/update_with_media
This is the code I have so far, yet despite numerous variations I can not get a successful upload.
public TwitterResponse UpdateStatus(string message, String fileName, String contentType, byte[] image)
{
RestClient client = new RestClient
{
Authority = TwitterConstants.Authority,
VersionPath = TwitterConstants.Version
};
message = HttpUtility.HtmlEncode(message);
client.AddHeader("content-type", "multipart/form-data");
client.AddField("status", message);
client.AddField("media[]", Convert.ToBase64String(image) + ";filename=" + fileName + ";type=" + contentType);
RestRequest request = new RestRequest
{
Credentials = this.Credentials,
Path = "statuses/update_with_media.json",
Method = Hammock.Web.WebMethod.Post
};
return new TwitterResponse(client.Request(request));
}
I am using Hammock to perform these requests.
Just to rule out possible other issues, I can successfully post a status update to Twitter using the update.json method.
I have also tried using the client.AddFile method and using Fiddler it looks like everything is in place. But the error message I keep getting back is
{"errors":[{"code":195,"message":"Missing or invalid url parameter"}]}
Instead of using native Twitter API, you can use TweeterSharp plugin available at Nuget.
Sample with description is written at this article by me Post message with image on twitter using C#
In particular this is the code snippet
using (var stream = new FileStream(imagePath, FileMode.Open))
{
var result = service.SendTweetWithMedia(new SendTweetWithMediaOptions
{
Status = message,
Images = new Dictionary<string, Stream> { { "john", stream } }
});
lblResult.Text = result.Text.ToString();
}
The complete demo is downloadable attached with the article, feel free to download.
Thanks
I've never used Hammock or or c#, but I know that we had a similar issue...
Our core twitter library worked for everything, but we couldn't get image uploads to work. It turns out that the OAuth library that our twitter lib depended on didn't calculate the signature properly when posting files. We had to update our oauth to get it work.
In our case the exact code we were trying to use worked fine once I substituted an updated OAuth.
If you are using an older version of OAuth, I would suggest looking for a more recent version, and pulling together a quick script to try with that.
Regarding that error message, it may be more of a red herring than a valid message - especially because it's not even listed on their error page:
https://dev.twitter.com/docs/error-codes-responses

Can I call a javascript function (from Classic ASP) from within my ASP.NET codebehind and obtain it's result?

From what I've seen on SO and elsewhere, IIS can run server-side Javascript code using it's JScript engine. In fact, in Classic ASP, it appears fairly easy to get this to work, as VBScript can call these functions directly. However, in .NET, I'm not sure how to procede.
I'm converting a web application written in Classic ASP into .NET. The application uses a javascript function to hash the users password. The result is queried against hashes stored in the database.
I'd like to continue to call this javascript function from my codebehind, so that the resulting hashes will continue to match.
Much of what i've seen online involves calling javascript using the RegisterStartupScript function, which won't work in this case, since I want the javascript to run on the server and I want to acquire the result of the javascript before I post back. Is this possible?
Yes and no.
You can call a javascript method through the ASP.NET backend by but the only way your going to get the result is to post it back through AJAX
so you can start a call and then wait around until the result comes back and handle the result.
This may or may not be what you want.
To answer your question directly, rewrite the hashing function in C# codebehind and call it there. Don't just port legacy code, improve it.
Here's a way to wrap the server side JScript function using a simple local "web service" call.
Add a JScript or ASP script that references the hashing function:
File: DoHash.asp
<!-- #include file="passwordHasher.js" -->
<%
Dim password
password = Request.Form("password")
Response.Write HashPassword(password)
%>
In your ASP.NET application add this method (and class if necessary somewhere relevant:
public class HashWrapper
{
public static string HashPasswordFromJScript(string password)
{
string url = "https://mysite.com/DoHash.asp";
string fields = "password=" + password;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
using(Stream rs = request.GetRequestStream())
{
using (MemoryStream ms = new MemoryStream())
{
using(BinaryWriter bw = new BinaryWriter(ms))
{
bw.Write(Encoding.UTF8.GetBytes(fields));
ms.WriteTo(rs);
ms.Flush();
}
}
}
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
if(response.StatusCode == HttpStatusCode.OK)
{
using(Stream rs = response.GetResponseStream())
{
using (StreamReader rr = new StreamReader(rs))
{
StringBuilder sb = new StringBuilder();
int bufferSize = 1024;
char[] read = new Char[bufferSize];
int count = rr.Read(read, 0, bufferSize);
while (count > 0)
{
sb.Append(read, 0, count);
count = rr.Read(read, 0, bufferSize);
}
return sb.ToString();
}
}
}
return null;
}
}
}
In the part of the application you need to hash a password just call:
string hashedPassword = HashWrapper.HashPasswordFromJScript(password);
It's not pretty but it'd get you by. I'm also presuming your site can encrypt traffic using SSL.
The best thing to do would be to not be afraid of the hash function. If you can figure out the algorithm and reimplement it in C#. Come up with some test cases to check you get the same results through both. It'll save you a lot of effort in the end.
Because classic ASP parses pages on a page-by-page basis, you can pick and choose what language you wrote your pages in. You could use any activescript language (perl was available that way at one point!)
In a .Net web app, the whole app needs to be in one language. So to use Jscript.Net, you'd need a separate project for your function. The project could compile to an assembly that you import into your web app, or it could be another web app and you communicate between the 2 via requests or web services. Either way, it's a lot of work.
Simon
Try to use JavaScript handle client-side behaviors and let VB/C# handle the server side calls.

Categories

Resources