/// <summary> /// Initializes a new instance of the <see cref="Message"/> class. /// </summary> /// <param name="address">The address the message is to be sent to.</param> /// <param name="data">The data to be sent in the message.</param> /// <param name="waitingForResponse">Whether the message is waiting for a response.</param> public Message(NodeDefinition address, BaseMessageData data, bool waitingForResponse) { _address = address; _data = data; _status = MessageStatus.Created; _id = GetNextId(); _waitingForResponse = waitingForResponse; }
/// <summary> /// Initializes a new instance of the <see cref="Message"/> class. /// </summary> /// <param name="responseTo">The message this is in response to.</param> /// <param name="data">The data to be sent in the message.</param> /// <param name="waitingForResponse">Whether the message is waiting for a response.</param> public Message(Message responseTo, BaseMessageData data, bool waitingForResponse) { _address = responseTo.Address; _inResponseTo = responseTo._id; _data = data; _status = MessageStatus.Created; _id = GetNextId(); _waitingForResponse = waitingForResponse; }
/// <summary> /// Decodes the received message. /// </summary> /// <param name="data">The data to be decoded.</param> private void DecodeMessage(byte[] data) { int index = 0; _id = ByteArrayHelper.ToUInt32(data, ref index); _inResponseTo = ByteArrayHelper.ToUInt32(data, ref index); _waitingForResponse = ByteArrayHelper.ToBoolean(data, ref index); _data = BaseMessageData.Decode(data, index); }
/// <summary> /// Attempts to merge the database chunks. /// </summary> private void AttemptMerge() { BaseMessageData message = null; _checkForMerge = false; _lock.EnterUpgradeableReadLock(); for (int i = 0; i < _chunks.Count - 1; ++i) { if (_chunks[i].Count + _chunks[i + 1].Count < _maxChunkItemCount / 2 && Equals(_chunks[i].End, _chunks[i + 1].Start)) { _checkForMerge = true; if (_node.Primary == null) { break; } Message canMerge = new Message(_node.Primary, new ChunkManagementRequest(), true); _node.SendDatabaseMessage(canMerge); canMerge.BlockUntilDone(); if (canMerge.Success && ((ChunkManagementResponse)canMerge.Response.Data).Result) { _lock.EnterWriteLock(); // Merging two chunks, do the merge and then alert the primary controller before doing anything else. _chunks[i].Merge(_chunks[i + 1]); _chunks.RemoveAt(i + 1); message = new ChunkMerge(_chunks[i].Start, _chunks[i].End); _lock.ExitWriteLock(); } break; } } _lock.ExitUpgradeableReadLock(); if (message != null) { Message sentMessage = new Message(_node.Primary, message, true); _node.SendDatabaseMessage(sentMessage); sentMessage.BlockUntilDone(); } }
/// <summary> /// Attempts to split the database chunks. /// </summary> private void AttemptSplit() { BaseMessageData message = null; _checkForSplit = false; _lock.EnterUpgradeableReadLock(); for (int i = 0; i < _chunks.Count; ++i) { if (_chunks[i].Count > _maxChunkItemCount) { _checkForSplit = true; if (_node.Primary == null) { break; } Message canSplit = new Message(_node.Primary, new ChunkManagementRequest(), true); _node.SendDatabaseMessage(canSplit); canSplit.BlockUntilDone(); if (canSplit.Success && ((ChunkManagementResponse)canSplit.Response.Data).Result) { _lock.EnterWriteLock(); // Spliting a chunk, do the split and then alert the primary controller before doing anything else. _chunks.Insert(i + 1, _chunks[i].Split()); message = new ChunkSplit(_chunks[i].Start, _chunks[i].End, _chunks[i + 1].Start, _chunks[i + 1].End); _lock.ExitWriteLock(); } break; } } _lock.ExitUpgradeableReadLock(); if (message != null) { Message sentMessage = new Message(_node.Primary, message, true); _node.SendDatabaseMessage(sentMessage); sentMessage.BlockUntilDone(); } }
private async void ReadMessages() { WebSocketReceiveResult webSocketReceiveResult = null; string lastMessage = null; try { readers.AddCount(); while (true) { await CheckConnectionOrWait(); bool readCompleted = false; try { webSocketReceiveResult = await clientWebSocket.ReceiveAsync(incomingData, readerTokenSource.Token); readCompleted = true; } catch (TaskCanceledException) { /* swallow */ } catch (ThreadAbortException) { /* swallow */ } catch (ObjectDisposedException) { /* swallow */ } catch (OperationCanceledException) { /* swallow */ } catch (WebSocketException) { communication.SendWarningMessage($"PubSub Websocket closed unexpectedly."); } catch (Exception ex) { communication.SendErrorMessage($"PubSub Exception: {ex.GetType().Name}"); errorHandler.LogMessageException(ex, ""); } if (generalTokenSource.IsCancellationRequested) { //We are quitting break; } if ((readerTokenSource?.IsCancellationRequested ?? true) || !readCompleted) { //We are just restarting reader, since it was intercepted with an exception or the reader token source was cancelled continue; } if (webSocketReceiveResult.Count < 1) { await Task.Delay(100, generalTokenSource.Token); continue; } lastMessage = Encoding.UTF8.GetString(incomingData, 0, webSocketReceiveResult.Count); while (!webSocketReceiveResult.EndOfMessage) { readCompleted = false; try { webSocketReceiveResult = await clientWebSocket.ReceiveAsync(incomingData, readerTokenSource.Token); readCompleted = true; } catch (TaskCanceledException) { /* swallow */ } catch (ThreadAbortException) { /* swallow */ } catch (ObjectDisposedException) { /* swallow */ } catch (OperationCanceledException) { /* swallow */ } catch (WebSocketException) { communication.SendWarningMessage($"PubSub Websocket closed unexpectedly."); } catch (Exception ex) { communication.SendErrorMessage($"PubSub Exception: {ex.GetType().Name}"); errorHandler.LogMessageException(ex, ""); } if (generalTokenSource.IsCancellationRequested) { //We are quitting break; } if ((readerTokenSource?.IsCancellationRequested ?? true) || !readCompleted) { //We are just restarting reader, since it was intercepted with an exception or the reader token source was cancelled break; } if (webSocketReceiveResult.Count < 1) { communication.SendWarningMessage($"WebSocketMessage returned no characters despite not being at end. {lastMessage}"); break; } lastMessage += Encoding.UTF8.GetString(incomingData, 0, webSocketReceiveResult.Count); } if (generalTokenSource.IsCancellationRequested) { //We are quitting break; } if ((readerTokenSource?.IsCancellationRequested ?? true) || !readCompleted) { //We are just restarting reader, since it was intercepted with an exception or the reader token source was cancelled continue; } BasicPubSubMessage message = JsonSerializer.Deserialize <BasicPubSubMessage>(lastMessage); switch (message.TypeString) { case "PONG": pongReceived = true; break; case "PING": await SendMessage(pongMessage); break; case "RECONNECT": communication.SendDebugMessage($"PubSub Reconnect Message Received"); breakConnection = true; break; case "RESPONSE": { PubSubResponseMessage response = JsonSerializer.Deserialize <PubSubResponseMessage>(lastMessage); PubSubMessage sentMessage = sentMessages.Where(x => x.Nonce == response.Nonce).FirstOrDefault(); if (!string.IsNullOrEmpty(response.ErrorString)) { if (sentMessage is not null) { communication.SendErrorMessage($"Error with message {JsonSerializer.Serialize(sentMessage)}: {response.ErrorString}"); } else { communication.SendErrorMessage($"Error with message <Unable To Locate>: {response.ErrorString}"); } } if (sentMessage is not null) { sentMessages.Remove(sentMessage); } } break; case "MESSAGE": { ListenResponse listenResponse = JsonSerializer.Deserialize <ListenResponse>(lastMessage); BaseMessageData messageData = JsonSerializer.Deserialize <BaseMessageData>(listenResponse.Data.Message); switch (messageData.TypeString) { case "reward-redeemed": ChannelPointMessageData channelPointMessageData = JsonSerializer.Deserialize <ChannelPointMessageData>(listenResponse.Data.Message); redemptionHandler.HandleRedemption(channelPointMessageData.Data); break; default: communication.SendErrorMessage($"Unsupported PubSub Message: {messageData.TypeString} - {listenResponse.Data.Message}"); break; } } break; default: communication.SendErrorMessage($"Unsupported PubSub Message Type: {message.TypeString} - {lastMessage}"); break; } } } catch (TaskCanceledException) { /* swallow */ } catch (ThreadAbortException) { /* swallow */ } catch (ObjectDisposedException) { /* swallow */ } catch (OperationCanceledException) { /* swallow */ } catch (Exception ex) { communication.SendErrorMessage($"PubSub Exception: {ex.GetType().Name}"); if (lastMessage is not null) { communication.SendErrorMessage($"Last PubSub Message: {lastMessage}"); } errorHandler.LogMessageException(ex, ""); } finally { readers.Signal(); } }