private void QueueCompleted(Task result, T queue) { if (queue.ReQueue) { lock (_Queues) _Queues.Add(queue); } if (queue.ReQueueAfterRunComplete) { lock (_ReQueues) _ReQueues.Add(queue); } if (result.IsFaulted) { OnTaskException?.Invoke(result.Exception, queue); } OnQueueComplete?.Invoke(result, queue); if (!queue.ReQueue && !queue.ReQueueAfterRunComplete) { queue.Dispose(); } lock (_Runnings) _Runnings.Remove(queue); if (RunAsParty) { if (RunningCount == 0 && MaxRun > 0) { OnQueueNextGroup?.Invoke(); RunNewQueue(); } } else { RunNewQueue(); } }
private void ScheduledTask_OnException(ScheduledTask task, Exception exception) { string message = $"An error occurred while executing {task.Name}"; WorkerLogger.Error(message, exception); Store($"{message}, Exception = {exception.Message}"); OnTaskException?.Invoke(this, new TaskExceptionEventArgs(task, exception)); }
protected virtual void NotifyException() { if (State == TaskState.Error) { if (OnTaskException != null) { OnTaskException.Invoke(this); } ExceptionWasNotified = true; } }
/// <summary> /// Initialize the connection and set up the handshake /// Topics: (https://dev.twitch.tv/docs/pubsub#topics) /// </summary> /// <param name="host">Host server to connect to</param> /// <param name="accessToken">Access token with the required scopes to listen for the desired topics</param> /// <param name="topics">Topics to handle</param> /// <returns></returns> public static async Task Start(string host, string accessToken, string[] topics) { try { InitComponents(); await ConnectAsync(host); _ = Task.Run(() => ProcessMessageQueue()); _ = Task.Run(() => Monitor()); await Heartbeat(); await Listen(accessToken, topics); } catch (Exception ex) { OnTaskException?.Invoke(new TaskExceptionArgs(ex, "Startup Failed")); throw ex; } }
/// <summary> /// Handle incoming websocket messages that are added to the message queue /// </summary> public static void ProcessMessageQueue() { CancellationToken cancellationToken = s_ProcessCancellationSource.Token; while (!cancellationToken.IsCancellationRequested) { if (s_MessageQueue.Count == 0) { Thread.Sleep(1); continue; } if (s_MessageQueue.TryTake(out string item)) { Payload response = JsonConvert.DeserializeObject <Payload>(item); OnPayload?.Invoke(response); switch (response.type) { case "PONG": { s_PongReceived = true; Task.Run(() => DelayedHeartbeat()); } break; case "RECONNECT": { OnServerRestart?.Invoke(); } break; case "RESPONSE": { PayloadResponse payloadResponse = JsonConvert.DeserializeObject <PayloadResponse>(item); if (payloadResponse.nonce != s_ListenNonce) { throw new AccessViolationException($"The nonce received does not match {s_ListenNonce} Unknown: {payloadResponse.nonce}"); } OnResponse?.Invoke(payloadResponse); } break; case "MESSAGE": { PayloadMessage payloadMessage = JsonConvert.DeserializeObject <PayloadMessage>(item); string topicKey = GetTopicKey(payloadMessage.data.topic); if (topicKey == "whispers") { JObject jobj = JObject.Parse(payloadMessage.data.message); JToken jtokenType = jobj.GetValue("type"); JToken jtokenData = jobj.GetValue("data"); JToken jtokenDataObject = jobj.GetValue("data_object"); string type = jtokenType.ToString(); try { #pragma warning disable 0618 Whispers.Data data = JsonConvert.DeserializeObject <Whispers.Data>(jtokenData.ToString()); Whispers.Data data_object = JsonConvert.DeserializeObject <Whispers.Data>(jtokenDataObject.ToString()); #pragma warning restore 0618 payloadMessage.data.message = JObject.FromObject(new { type, data, data_object }).ToString().Replace("\n", "").Replace("\r", ""); if (s_TopicEvents.TryGetValue(topicKey, out Action <IPayload> value)) { value?.Invoke(payloadMessage); } } catch (Exception ex) { OnTaskException?.Invoke(new TaskExceptionArgs(ex, "ProcessMessageQueue Whisper")); } } else { if (s_TopicEvents.TryGetValue(topicKey, out Action <IPayload> value)) { value?.Invoke(payloadMessage); } } } break; default: break; } } } _ = InvokeReconnectWithBackoff(ReconnectReason.DefaultBreak); }
/// <summary> /// Monitor incoming websocket messages and adds them to a message queue /// </summary> /// <returns></returns> public static async Task Monitor() { CancellationToken cancellationToken = s_CancellationSource.Token; while (cancellationToken.IsCancellationRequested == false) { try { if ((s_WebSocket.State == WebSocketState.Open || s_WebSocket.State == WebSocketState.CloseSent) && cancellationToken.IsCancellationRequested == false) { ArraySegment <byte> buffer = new ArraySegment <byte>(new byte[1024]); WebSocketReceiveResult result = await s_WebSocket.ReceiveAsync(buffer, cancellationToken); if (result == null) { continue; } if (result.MessageType != WebSocketMessageType.Text) { Thread.Sleep(1); continue; } if (result.EndOfMessage == false) { s_Message += Encoding.UTF8.GetString(buffer.Array, 0, result.Count); } else { s_Message += Encoding.UTF8.GetString(buffer.Array, 0, result.Count); s_MessageQueue.Add(s_Message); s_Message = string.Empty; } } else if (s_WebSocket.State == WebSocketState.Closed) { await InvokeReconnectWithBackoff(ReconnectReason.Closed); break; } else if (s_WebSocket.State == WebSocketState.Aborted) { await InvokeReconnectWithBackoff(ReconnectReason.Aborted); break; } } catch (OperationCanceledException ex) { OnTaskException?.Invoke(new TaskExceptionArgs(ex, "OperationCanceledException")); } catch (WebSocketException ex) { OnTaskException?.Invoke(new TaskExceptionArgs(ex, "WebSocketException")); } catch (Exception ex) { OnTaskException?.Invoke(new TaskExceptionArgs(ex, "Monitor")); await InvokeReconnectWithBackoff(ReconnectReason.Exception); break; } } await InvokeReconnectWithBackoff(ReconnectReason.OperationCanceled); }