Timer to track websocket sharp messages in c# - c#

I am using a websocket sharp dll in my windows application to get messages from a GDAX server. Everything is working fine so far - the messages are coming and i am processing them. The point where I am stuck is when the messages stops coming. At least I don't find anything in the WebSocket.OnMessage Event(https://github.com/sta/websocket-sharp) that can help me in tracking when the messages are stopped (I tried emitonping also)
Now the messages I received have a message type 'Heartbeat' which is sent every second. I want to add a separate timer control to check if the heartbeat messages are coming every second or not and if it stops coming then I will need to reconnect the server again. But since nothing happens when the messages stops coming how do i track it, where should I put the timer code to check when heartbeat messages stops coming?
I hope I could explain the situation wherein I am struck. If someone is eager to help me and needs more inputs please let me know.
Update
private void _3_Load(object sender, EventArgs e)
{
ConnectAndGetWebsocketFeedMessages();
}
public delegate void WSOpen(string text);
public delegate void WSMessage(string message);
public delegate void WSError(string text);
public delegate void WSClose(string text);
private static string _endPoint = "wss://ws-feed.gdax.com";
WebSocket ws = new WebSocket(_endPoint);
private bool IsConnected { get; set; }
private string ProductId { get; set; }
string productId = "LTC-EUR";
ConcurrentQueue<string> concurrentQueue = new ConcurrentQueue<string>();
public void SetWebSocketSharpEvents()
{
ws.Log.Level = LogLevel.Trace;
ws.OnOpen += (sender, e) =>
{
IsConnected = true;
OnWSOpen("Connection Status :: Connected *********");
};
ws.EmitOnPing = true;
ws.OnMessage += (sender, e) =>
{
if (e.IsPing)
{
OnWSMessage("ping received");
}
else
{
OnWSMessage(e.Data);
}
};
ws.OnError += (sender, e) =>
{
IsConnected = false;
OnWSError(e.Message); //An exception has occurred during an OnMessage event. An error has occurred in closing the connection.
if (ws.IsAlive)
ws.Close();
};
ws.OnClose += (sender, e) =>
{
IsConnected = false;
OnWSClose("Close");
};
ws.ConnectAsync();
}
private void ConnectAndGetWebsocketFeedMessages()
{
SetWebSocketSharpEvents();
}
private void SubscribeProduct(string sProductID)
{
if (IsConnected)
{
ProductId = sProductID;
string data = "{\"type\": \"subscribe\", \"product_ids\": [\"" + sProductID + "\"]}";
ws.Send(data);
ws.Send("{\"type\": \"heartbeat\", \"on\": true}");
}
}
void OnWSOpen(string text)
{
SubscribeProduct(productId);
timer1.Interval = 1000;
timer1.Tick += timer1_Tick;
timer1.Start();
}
DateTime lastHeartbeatTime = DateTime.MinValue;
bool isTimerStart = false;
void OnWSMessage(string message)
{
concurrentQueue.Enqueue(message);
SaveHeartbeatMessageTime(message);
ProcessMessage(message);
}
private void SaveHeartbeatMessageTime(string jsonString)
{
var jToken = JToken.Parse(jsonString);
var typeToken = jToken["type"];
var type = typeToken.ToString();
if (type == "heartbeat")
{
lastHeartbeatTime = DateTime.Now;
this.Invoke(new MethodInvoker(delegate()
{
lbllastheartbeat.Text = lastHeartbeatTime.ToLongTimeString();
}));
}
}
private void ProcessMessage(string message) { }
void OnWSError(string text) { }
void OnWSClose(string text) { }
bool isMessagesReceived = false;
private void timer1_Tick(object sender, EventArgs e) // it stops working as soon as lbllastheartbeat gets some value
{
DateTime currentTime = DateTime.Now;
TimeSpan duration = currentTime.Subtract(lastHeartbeatTime);
this.Invoke(new MethodInvoker(delegate()
{
lblNow.Text = currentTime.ToLongTimeString();
}));
if (Int16.Parse(duration.ToString("ss")) > 1)
{
// reconnect here
}
}
Edit
I am using windows form timer control and it keeps on calling timer1_Tick method and does not call OnWSMessage method. How do I ensure that both run parallel and if any message is missed or the message stops coming then it reconnects?
Edit2
The solutions provided below suggests to add the timer functionality in onMessage event but what will happen if I do not receive messages? If the messages are not received then the code does not do anything. I have taken a global variable and whenever a message comes it adds the time in that variable. Now I want to run a separate timer control which will check whether there is anything in that variable and if its value i.e difference of seconds is more than 1 then do something else keep on checking.
Is there anyone who can look into this and advise please.
Update2: I still want to do this with windows.timer control and not threading.timer. I have taken two labels in my windows app, lbllastheartbeat (to show the time when heartbeat message is received) and lblNow (to show the current time when timer is called).
Requirement - My timer will check if any heartbeat message is missed and that is done through the 'lastHeartbeatTime' variable which stores the time when the heartbeat message is received.
I would appreciate if anyone can review my code and suggest what or where I am doing wrong.

The answer has already been given - you need to start timer which will fire after your timeout period when you receive message, and reset that timer every time you receive message. But it seems you want code example, so here it is (with comments):
System.Threading.Timer _timeoutTimer;
private readonly object _timeoutTimerLock = new object();
private void ResetTimeoutTimer() {
// if you are sure you will never access this from multiple threads at the same time - remove lock
lock (_timeoutTimerLock) {
// initialize or reset the timer to fire once, after 2 seconds
if (_timeoutTimer == null)
_timeoutTimer = new System.Threading.Timer(ReconnectAfterTimeout, null, TimeSpan.FromSeconds(2), Timeout.InfiniteTimeSpan);
else
_timeoutTimer.Change(TimeSpan.FromSeconds(2), Timeout.InfiniteTimeSpan);
}
}
private void StopTimeoutTimer() {
// if you are sure you will never access this from multiple threads at the same time - remove lock
lock (_timeoutTimerLock) {
if (_timeoutTimer != null)
_timeoutTimer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
}
}
private void ReconnectAfterTimeout(object state) {
// reconnect here
}
public void SetWebSocketSharpEvents() {
ws.Log.Level = LogLevel.Trace;
ws.OnOpen += (sender, e) => {
// start timer here so that if you don't get first message after 2 seconds - reconnect
ResetTimeoutTimer();
IsConnected = true;
OnWSOpen("Connection Status :: Connected *********");
};
ws.EmitOnPing = true;
ws.OnMessage += (sender, e) => {
// and here
ResetTimeoutTimer();
if (e.IsPing) {
OnWSMessage("ping received");
}
else {
OnWSMessage(e.Data);
}
};
ws.OnError += (sender, e) => {
// stop it here
StopTimeoutTimer();
IsConnected = false;
OnWSError(e.Message); //An exception has occurred during an OnMessage event. An error has occurred in closing the connection.
if (ws.IsAlive)
ws.Close();
};
ws.OnClose += (sender, e) => {
// and here
StopTimeoutTimer();
IsConnected = false;
OnWSClose("Close");
};
ws.ConnectAsync();
}

from your question what i understand is , your message is sending after every seconds , but the problem is only when it stop you want to know and run it again, if it like that , you just apply timer and check for every seconds if the message not sent after a second or more (check sentMessage() Method set a boolean if message sent it should give true otherwise false) , than give the command to reconnect the server again .

Related

How to handle DataReceived

Please see my code below, that I am trying to return back to method that I registered the port's DataReceived event. Basically, If I recieve data from port before read time out. I will return back where I registered DataReceived event and degister and continue process. I am trying to do it with while loop. But not sure if it is accurate, and it is the way that has to be done
or if there is any other way to do this.
public class CommClass{
private static byte[] portReturn = null;
private void setUpDevice()
{
byte[] command = { 0x11,0X51 };
try
{
port.DataReceived += new SerialDataReceivedEventHandler(serialPortDataReceived);
port.Write(command, 0, command.Length);
while (portReturn == null) { } //Not sure if this will work. If I receive data before times out I do not want to wait in the loop.
port.DataReceived -= serialPortDataReceived;
}
catch(Exception ex)
{
//to do
}
}
private void serialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var servicePort = (SerialPort)sender;
portReturn = servicePort.ReadByte();
return;
}
}
You code will technically work; however, your while loop will max out your CPU while you're waiting for data to come in, which is not what you want. I recommend using a ManualResetEvent here to let you wait to receive data in a CPU friendly way. You can read more about them here
public class CommClass
{
private static byte[] portReturn = null;
// ManualResetEvents are great for signaling events across threads
private static ManualResetEvent dataReceivedEvent = new ManualResetEvent(false);
private void setUpDevice()
{
byte[] command = { 0x11,0X51 };
try
{
port.DataReceived += new SerialDataReceivedEventHandler(serialPortDataReceived);
port.Write(command, 0, command.Length);
// Wait for the event to be set without spinning in a loop.
// Can also specify a timeout period to wait in case the data never comes.
dataReceivedEvent.WaitOne();
// Reset the event so that you can use it again later if necessary
dataReceivedEvent.Reset();
port.DataReceived -= serialPortDataReceived;
}
catch(Exception ex)
{
//to do
}
}
private void serialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var servicePort = (SerialPort)sender;
portReturn = servicePort.ReadByte();
// Set the event to let the main thread know you have received data
dataReceivedEvent.Set();
}
}

C# .NET - Using Background Thread but GUI is Unresponsive

I'm implementing a Client who can ask a service for a certain action and also an abort button for this action.
Once I run the action using background thread the abort button should become active, but instead the entire GUI is stuck with the mouse icon as hour glass (Should mention that the action is still indeed occurring).
private void actionButton_Click(object sender, EventArgs e)
{
Run(RunMode.Action);
}
private void Run(RunMode runMode)
{
abortButton.Enabled = true;
try
{
var name = "ds_file";
var url = UrlProvider.BuildRequestUrl(runMode, name);
StartLoading($"Running request: {url}");
RunWorker(url);
}
catch (Exception ex)
{
AddToLog(ex.ToString());
PopError("Failed to run, see error in log box");
}
}
private void RunWorker(string url)
{
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
DatabaseHelper.DisableAllJobs();
HttpRequestsHandler.HttpGet(url);
DatabaseHelper.EnableRegularJobs();
};
worker.RunWorkerCompleted += (sender, args) =>
{
StopLoading();
abortButton.Enabled = false;
if (args.Error != null)
{
PopError("Failed to run, see error in log box");
AddToLog(args.Error.ToString());
}
else
{
PopInfo("Completed successfully");
}
};
worker.RunWorkerAsync();
}
What am I doing wrong?
Thanks
Following example run background service every 10 seconds to update GUI. You can modify it as you wish. By running your thread as async task your GUI never get hang.
public frm_testform()
{
InitializeComponent();
dispatcherTimer_Tick().DoNotAwait();
}
private async Task dispatcherTimer_Tick()
{
DispatcherTimer timer = new DispatcherTimer();
TaskCompletionSource<bool> tcs = null;
EventHandler tickHandler = (s, e) => tcs.TrySetResult(true);
timer.Interval = TimeSpan.FromSeconds(10);
timer.Tick += tickHandler;
timer.Start();
while (true)
{
tcs = new TaskCompletionSource<bool>();
await Task.Run(() =>
{
// Run your background service and UI update here
await tcs.Task;
}
}
It indeed turns out I had controls.enable = false in some part of the code (I really thought it totally meant for something else), thank you all for your help!!

How to check message arrival in service bus at every 20 seconds?

I am using Service Bus of azure which will hold my list of messages means messages can enter in service bus at any time.
So i want to keep a watch on my service bus to check that whether any message is there in service or not.It is like i just want to keep a watch on my service bus regarding message arrival in my service bus at interval 0f 20 seconds.
In Every 20 Seconds i would like to check message arrival in my service bus and this i want to perform in background asynchronously.
I want to call below method in every 20 seconds in background:
private static void ReceiveMessages()
{
// For PeekLock mode (default) where applications require "at least once" delivery of messages
SubscriptionClient agentSubscriptionClient = SubscriptionClient.Create(TopicName, "AgentSubscription");
BrokeredMessage message = null;
while (true)
{
try
{
//receive messages from Agent Subscription
message = agentSubscriptionClient.Receive(TimeSpan.FromSeconds(5));
if (message != null)
{
Console.WriteLine("\nReceiving message from AgentSubscription...");
Console.WriteLine(string.Format("Message received: Id = {0}, Body = {1}", message.MessageId, message.GetBody<string>()));
// Further custom message processing could go here...
message.Complete();
}
else
{
//no more messages in the subscription
break;
}
}
catch (MessagingException e)
{
if (!e.IsTransient)
{
Console.WriteLine(e.Message);
throw;
}
else
{
HandleTransientErrors(e);
}
}
}
// For ReceiveAndDelete mode, where applications require "best effort" delivery of messages
SubscriptionClient auditSubscriptionClient = SubscriptionClient.Create(TopicName, "AuditSubscription", ReceiveMode.ReceiveAndDelete);
while (true)
{
try
{
message = auditSubscriptionClient.Receive(TimeSpan.FromSeconds(5));
if (message != null)
{
Console.WriteLine("\nReceiving message from AuditSubscription...");
Console.WriteLine(string.Format("Message received: Id = {0}, Body = {1}", message.MessageId, message.GetBody<string>()));
// Further custom message processing could go here...
}
else
{
Console.WriteLine("\nno more messages in the subscription");
//no more messages in the subscription
break;
}
}
catch (MessagingException e)
{
if (!e.IsTransient)
{
Console.WriteLine(e.Message);
throw;
}
}
}
agentSubscriptionClient.Close();
auditSubscriptionClient.Close();
}
So can anybody tell me how do i call this above method every 20 seconds?
The most beginner-friendly solution is:
Drag a Timer from the Toolbox, give it a Name, set your desired Interval and set "Enabled" to True. Then double click the Timer and Visual Studio (or whatever you are using) will write you the following Code:
private void wait_Tick(object sender, EventArgs e)
{
refreshText(); //add the method you want to call here.
}
or this
private Timer timer1;
public void InitTimer()
{
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 2000; // in miliseconds
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
isonline()
}

EWS streaming notifications not received

Afternoon all,
I have a windows service which subscribes to an Office365 email account and awaits new emails, when they arrive it processes their attachments, and all is well with the world.
But... for some reason, the applications stops receiving notifications after an undetermined amount of time.
I have handled the 'OnDisconnect' event and reestablish a connection as shown in the below code, but that doesnt seem to be fixing this issue. The windows service continues to run fine, and if I restart the service everything is good again, until is failed again.
This is the my class for running exchange:
public class ExchangeConnection
{
static readonly ExchangeService Service = Exchange.Service.ConnectToService(UserDataFromConsole.GetUserData(), new TraceListener());
public event EmailReceivedHandler OnEmailReceived;
public ExchangeConnection()
{
}
public void Open()
{
SetStreamingNotifications(Service);
var signal = new AutoResetEvent(false);
signal.WaitOne();
}
private void SetStreamingNotifications(ExchangeService service)
{
var streamingsubscription = service.SubscribeToStreamingNotifications(new FolderId[] { WellKnownFolderName.Inbox }, EventType.NewMail);
var connection = new StreamingSubscriptionConnection(service, 30);
connection.AddSubscription(streamingsubscription);
connection.OnNotificationEvent += OnEvent;
connection.OnSubscriptionError += OnError;
connection.OnDisconnect += OnDisconnect;
connection.Open();
}
public void MoveEmail(ItemId id, String folderName = "Archived Emails")
{
var rootFolder = Folder.Bind(Service, WellKnownFolderName.Inbox);
var archivedFolder = rootFolder.FindFolders(new FolderView(100)).FirstOrDefault(x => x.DisplayName == folderName);
if (archivedFolder == null)
{
archivedFolder = new Folder(Service) { DisplayName = folderName };
archivedFolder.Save(WellKnownFolderName.Inbox);
}
Service.MoveItems(new List<ItemId> {id}, archivedFolder.Id);
}
#region events
private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
{
//The connection is disconnected every 30minutes, and we are unable to override this,
//so when we get disconnected we just need to reconnect again.
var connection = (StreamingSubscriptionConnection)sender;
connection.Open();
}
private void OnEvent(object sender, NotificationEventArgs args)
{
var subscription = args.Subscription;
// Loop through all item-related events.
foreach (var notification in args.Events)
{
switch (notification.EventType)
{
case EventType.NewMail:
if (notification is ItemEvent)
{
var email = Item.Bind(Service, new ItemId(((ItemEvent) notification).ItemId.UniqueId));
OnEmailReceived(new EmailReceivedArgs((EmailMessage)email));
}
break;
}
}
}
private void OnError(object sender, SubscriptionErrorEventArgs args)
{
var e = args.Exception;
Logger.LogException(e,LogEventType.Error);
}
#endregion events
}
Any help would be great, thanks.
EDIT:
After improving the error logging I have found this exception occuring:
Exception: The specified subscription was not found.
Any ideas what is causing this?
With Office365 you need to make sure you deal with affinity see http://msdn.microsoft.com/en-us/library/office/dn458789(v=exchg.150).aspx . Adding those headers will ensure your requests will always routed to the correct servers.
Cheers
Glen

Using recorded wave file (NAudio)

This is the code I use to record an audio file:
internal class AudioRecorder
{
public WaveIn waveSource = null;
public WaveFileWriter waveFile = null;
public string RECORDING_PATH;
public AudioRecorder(string fileName)
{
RECORDING_PATH = fileName;
}
public void Start()
{
waveSource = new WaveIn();
waveSource.WaveFormat = new WaveFormat(44100, 1);
waveSource.DeviceNumber = 0;
waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
waveFile = new WaveFileWriter(RECORDING_PATH, waveSource.WaveFormat);
System.Timers.Timer t = new System.Timers.Timer(30000);
t.Elapsed += new ElapsedEventHandler(Stop);
waveSource.StartRecording();
t.Start();
}
private void Stop(object sender, ElapsedEventArgs args)
{
waveSource.StopRecording();
}
private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
{
if (waveFile != null)
{
waveFile.Write(e.Buffer, 0, e.BytesRecorded);
waveFile.Flush();
}
}
private void waveSource_RecordingStopped(object sender, StoppedEventArgs e)
{
if (waveSource != null)
{
waveSource.Dispose();
waveSource = null;
}
if (waveFile != null)
{
waveFile.Dispose();
waveFile = null;
}
}
}
In the main method I do:
AudioRecorder r = new AudioRecorder(dialog.FileName);
r.Start();
FileInfo file = new FileInfo(r.RECORDING_PATH);
// Do somehting with the recorded audio //
The problem is that when I do r.Start() the thread does not block and keeps running. So I get a corrupt file error. When I try things like Thread.Sleep to keep the thread waiting until recording finishes, this time the AudioRecorder code does not work well (i.e. recording never finishes).
Any ideas about what should I do to correctly wait the recording to finish so that I can safely use the recorded file ?
If you want to record for 30 seconds exactly, just call StopRecording in the DataAvailable event handler once you have enough data. There is absolutely no need for a complicated threading strategy. I do exactly this in the open source .NET voice recorder application.
Dispose the WaveFileWriter in the RecordingStopped event.
If you absolutely must have a blocking call, then use WaveInEvent, and wait on an event which is set in the RecordingStopped handler, as suggested by Rene. By using WaveInEvent, you remove the need for windows message pump to be operational.
You use a ManualResetEvent to wait for the Stop event to be called, giving other threads a change to proceed.
I've only added the new bits...
internal class AudioRecorder
{
private ManualResetEvent mre = new ManualResetEvent(false);
public void Start()
{
t.Start();
while (!mre.WaitOne(200))
{
// NAudio requires the windows message pump to be operational
// this works but you better raise an event
Application.DoEvents();
}
}
private void Stop(object sender, ElapsedEventArgs args)
{
// better: raise an event from here!
waveSource.StopRecording();
}
private void waveSource_RecordingStopped(object sender, EventArgs e)
{
/// ... your code here
mre.Set(); // signal thread we're done!
}
It is good idea to avoid any multi-threaded code if it is not required and Mark's answer is explaining this perfectly.
However, if you are writing a windows application and the requirement is to record 30 seconds than it is a must not to block a main thread in waiting (for 30 seconds). The new async C# feature can be very handy here. It will allow you to keep code logic straightforward and implement waiting in a very efficient way.
I have modified your code slightly to show how the async feature can be used in this case.
Here is the Record method:
public async Task RecordFixedTime(TimeSpan span)
{
waveSource = new WaveIn {WaveFormat = new WaveFormat(44100, 1), DeviceNumber = 0};
waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
waveFile = new WaveFileWriter(RECORDING_PATH, waveSource.WaveFormat);
waveSource.StartRecording();
await Task.Delay(span);
waveSource.StopRecording();
}
Example of using Record from click handler of WPF app:
private async void btnRecord_Click(object sender, RoutedEventArgs e)
{
try
{
btnRecord.IsEnabled = false;
var fileName = Path.GetTempFileName() + ".wav";
var recorder = new AudioRecorder(fileName);
await recorder.RecordFixedTime(TimeSpan.FromSeconds(5));
Process.Start(fileName);
}
finally
{
btnRecord.IsEnabled = true;
}
}
However, you have to watch out for timing here. Task.Delay does not guarantee that it will continue execution after the exact specified time span. You might get records slightly longer than is required.

Categories