public void Notify(string @event, object @internal, NotifyData data, byte[] payload) { _logger.LogDebug($"notify() [event:{@event}]"); if (_closed) { throw new InvalidStateException("PayloadChannel closed"); } var notification = new { @event, @internal, data }; var ns1Bytes = Netstring.Encode(notification.ToCamelCaseJson()); var ns2Bytes = Netstring.Encode(payload); if (ns1Bytes.Length > NsMessageMaxLen) { throw new Exception("PayloadChannel notification too big"); } if (ns2Bytes.Length > NsMessageMaxLen) { throw new Exception("PayloadChannel payload too big"); } Loop.Default.Sync(() => { try { // This may throw if closed or remote side ended. _producerSocket.Write(ns1Bytes, ex => { if (ex != null) { _logger.LogError(ex, "_producerSocket.Write() | error"); } }); } catch (Exception ex) { _logger.LogWarning($"notify() | sending notification failed: {ex}"); return; } try { // This may throw if closed or remote side ended. _producerSocket.Write(ns2Bytes, ex => { if (ex != null) { _logger.LogError(ex, "_producerSocket.Write() | error"); } }); } catch (Exception ex) { _logger.LogWarning($"notify() | sending notification failed: {ex}"); return; } }); }
private void ConsumerSocketOnData(ArraySegment <byte> data) { if (_recvBuffer == null) { _recvBuffer = data; } else { var newBuffer = new byte[_recvBuffer.Value.Count + data.Count]; Array.Copy(_recvBuffer.Value.Array, _recvBuffer.Value.Offset, newBuffer, 0, _recvBuffer.Value.Count); Array.Copy(data.Array, data.Offset, newBuffer, _recvBuffer.Value.Count, data.Count); _recvBuffer = new ArraySegment <byte>(newBuffer); } if (_recvBuffer.Value.Count > NsPayloadMaxLen) { _logger.LogError("ConsumerSocketOnData() | receiving buffer is full, discarding all data into it"); // Reset the buffer and exit. _recvBuffer = null; return; } //_logger.LogError($"ConsumerSocketOnData: {buffer}"); var netstring = new Netstring(_recvBuffer.Value); try { var nsLength = 0; foreach (var payload in netstring) { nsLength += payload.NetstringLength; ProcessMessage(payload); } if (nsLength > 0) { if (nsLength == _recvBuffer.Value.Count) { // Reset the buffer. _recvBuffer = null; } else { _recvBuffer = new ArraySegment <byte>(_recvBuffer.Value.Array, _recvBuffer.Value.Offset + nsLength, _recvBuffer.Value.Count - nsLength); } } } catch (Exception ex) { _logger.LogError($"ConsumerSocketOnData() | invalid netstring data received from the worker process:{ex}"); // Reset the buffer and exit. _recvBuffer = null; return; } }
private void ConsumerSocketOnData(ArraySegment <byte> data) { // 数据回调通过单一线程进入,所有 _recvBuffer 是线程安全的。 if (_recvBuffer == null) { _recvBuffer = data; } else { var newBuffer = new byte[_recvBuffer.Value.Count + data.Count]; Array.Copy(_recvBuffer.Value.Array, _recvBuffer.Value.Offset, newBuffer, 0, _recvBuffer.Value.Count); Array.Copy(data.Array, data.Offset, newBuffer, _recvBuffer.Value.Count, data.Count); _recvBuffer = new ArraySegment <byte>(newBuffer); } if (_recvBuffer.Value.Count > NsPayloadMaxLen) { _logger.LogError("ConsumerSocketOnData() | Receiving buffer is full, discarding all data into it"); // Reset the buffer and exit. _recvBuffer = null; return; } var netstring = new Netstring(_recvBuffer.Value); try { var nsLength = 0; foreach (var payload in netstring) { nsLength += payload.NetstringLength; var payloadString = Encoding.UTF8.GetString(payload.Data.Array, payload.Data.Offset, payload.Data.Count); try { // We can receive JSON messages (Channel messages) or log strings. switch (payloadString[0]) { // 123 = '{' (a Channel JSON messsage). case '{': ThreadPool.QueueUserWorkItem(_ => { ProcessMessage(payloadString); }); break; // 68 = 'D' (a debug log). case 'D': if (!payloadString.Contains("(trace)")) { _logger.LogDebug($"ConsumerSocketOnData() | [pid:{_processId}] { payloadString }"); } break; // 87 = 'W' (a warn log). case 'W': if (!payloadString.Contains("no suitable Producer")) { _logger.LogWarning($"ConsumerSocketOnData() | [pid:{_processId}] { payloadString }"); } break; // 69 = 'E' (an error log). case 'E': _logger.LogError($"ConsumerSocketOnData() | [pid:{_processId}] { payloadString }"); break; // 88 = 'X' (a dump log). case 'X': _logger.LogDebug($"ConsumerSocketOnData() | [pid:{_processId}] { payloadString }"); break; default: _logger.LogWarning($"ConsumerSocketOnData() | Worker [pid:{_processId}] unexpected data, payload:{ payloadString }"); break; } } catch (Exception ex) { _logger.LogError(ex, $"ConsumerSocketOnData() | Received invalid message from the worker process, payload: {payloadString}"); // Reset the buffer and exit. _recvBuffer = null; return; } } if (nsLength > 0) { if (nsLength == _recvBuffer.Value.Count) { // Reset the buffer. _recvBuffer = null; } else { _recvBuffer = new ArraySegment <byte>(_recvBuffer.Value.Array, _recvBuffer.Value.Offset + nsLength, _recvBuffer.Value.Count - nsLength); } } } catch (Exception ex) { _logger.LogError(ex, $"ConsumerSocketOnData() | Invalid netstring data received from the worker process."); // Reset the buffer and exit. _recvBuffer = null; return; } }
public Task <string?> RequestAsync(MethodId methodId, object? @internal = null, object?data = null) { if (_closed) { throw new InvalidStateException("Channel closed"); } var method = methodId.GetEnumStringValue(); var id = InterlockedExtensions.Increment(ref _nextId); // NOTE: For testinng //_logger.LogDebug($"RequestAsync() | [Method:{method}, Id:{id}]"); var requestMesssge = new RequestMessage { Id = id, Method = method, Internal = @internal, Data = data, }; var nsBytes = Netstring.Encode(requestMesssge.ToCamelCaseJson()); if (nsBytes.Length > NsMessageMaxLen) { throw new Exception("Channel request too big"); } var tcs = new TaskCompletionSource <string?>(); var sent = new Sent { RequestMessage = requestMesssge, Resolve = data => { if (!_sents.TryRemove(id, out var _)) { tcs.TrySetException(new Exception($"Received response does not match any sent request [id:{id}]")); return; } tcs.TrySetResult(data); }, Reject = e => { if (!_sents.TryRemove(id, out var _)) { tcs.TrySetException(new Exception($"Received response does not match any sent request [id:{id}]")); return; } tcs.TrySetException(e); }, Close = () => { tcs.TrySetException(new InvalidStateException("Channel closed")); }, }; if (!_sents.TryAdd(id, sent)) { throw new Exception($"Error add sent request [id:{id}]"); } tcs.WithTimeout(TimeSpan.FromSeconds(15 + (0.1 * _sents.Count)), () => _sents.TryRemove(id, out var _)); Loop.Default.Sync(() => { try { // This may throw if closed or remote side ended. _producerSocket.Write(nsBytes, ex => { if (ex != null) { _logger.LogError(ex, "_producerSocket.Write() | Error"); sent.Reject(ex); } }); } catch (Exception ex) { _logger.LogError(ex, "_producerSocket.Write() | Error"); sent.Reject(ex); } }); return(tcs.Task); }
private void ConsumerSocketOnData(ArraySegment <byte> data) { if (_recvBuffer == null) { _recvBuffer = data; } else { var newBuffer = new byte[_recvBuffer.Value.Count + data.Count]; Array.Copy(_recvBuffer.Value.Array, _recvBuffer.Value.Offset, newBuffer, 0, _recvBuffer.Value.Count); Array.Copy(data.Array, data.Offset, newBuffer, _recvBuffer.Value.Count, data.Count); _recvBuffer = new ArraySegment <byte>(newBuffer); } if (_recvBuffer.Value.Count > NsPayloadMaxLen) { _logger.LogError("ConsumerSocketOnData() | receiving buffer is full, discarding all data into it"); // Reset the buffer and exit. _recvBuffer = null; return; } //_logger.LogError($"ConsumerSocketOnData: {buffer}"); var netstring = new Netstring(_recvBuffer.Value); try { var nsLength = 0; foreach (var payload in netstring) { nsLength += payload.NetstringLength; var payloadString = Encoding.UTF8.GetString(payload.Data.Array, payload.Data.Offset, payload.Data.Count); try { // We can receive JSON messages (Channel messages) or log strings. switch (payloadString[0]) { // 123 = '{' (a Channel JSON messsage). case '{': ProcessMessage(payloadString); break; // 68 = 'D' (a debug log). case 'D': //if (!payloadString.Contains("(trace)")) _logger.LogError($"ConsumerSocketOnData() | [pid:{_processId}] { payloadString }"); break; // 87 = 'W' (a warn log). case 'W': _logger.LogWarning($"ConsumerSocketOnData() | [pid:{_processId}] { payloadString }"); break; // 69 = 'E' (an error log). case 'E': _logger.LogError($"ConsumerSocketOnData() | [pid:{_processId}] { payloadString }"); break; // 88 = 'X' (a dump log). case 'X': // eslint-disable-next-line no-console _logger.LogDebug($"ConsumerSocketOnData() | [pid:{_processId}] { payloadString }"); break; default: // eslint-disable-next-line no-console _logger.LogWarning($"ConsumerSocketOnData() | worker[pid:{_processId}] unexpected data:{ payloadString }"); break; } } catch (Exception ex) { _logger.LogError($"ConsumerSocketOnData() | received invalid message from the worker process:{ex}\ndata: {payloadString}"); // Reset the buffer and exit. _recvBuffer = null; return; } } if (nsLength > 0) { if (nsLength == _recvBuffer.Value.Count) { // Reset the buffer. _recvBuffer = null; } else { _recvBuffer = new ArraySegment <byte>(_recvBuffer.Value.Array, _recvBuffer.Value.Offset + nsLength, _recvBuffer.Value.Count - nsLength); } } } catch (Exception ex) { _logger.LogError($"ConsumerSocketOnData() | invalid netstring data received from the worker process:{ex}"); // Reset the buffer and exit. _recvBuffer = null; return; } }
public Task <string?> RequestAsync(MethodId methodId, object? @internal = null, object?data = null) { var method = methodId.GetEnumStringValue(); var id = _nextId < Int32.MaxValue ? ++_nextId : (_nextId = 1); // TODO: (alby)线程同步 _logger.LogDebug($"RequestAsync() | [method:{method}, id:{id}]"); if (_closed) { throw new InvalidStateException("Channel closed"); } var requestMesssge = new RequestMessage { Id = id, Method = method, Internal = @internal, Data = data, }; var nsBytes = Netstring.Encode(requestMesssge.ToCamelCaseJson()); if (nsBytes.Length > NsMessageMaxLen) { throw new Exception("Channel request too big"); } var tcs = new TaskCompletionSource <string?>(); var sent = new Sent { RequestMessage = requestMesssge, Close = () => { if (!_sents.Remove(id)) { return; } tcs.TrySetException(new InvalidStateException("Channel closed")); }, Resolve = data => { if (!_sents.Remove(id)) { return; } tcs.TrySetResult(data); }, Reject = e => { if (!_sents.Remove(id)) { return; } tcs.TrySetException(e); }, }; _sents.Add(id, sent); tcs.WithTimeout(TimeSpan.FromSeconds(15 + (0.1 * _sents.Count)), () => _sents.Remove(id)); Loop.Default.Sync(() => { try { // This may throw if closed or remote side ended. _producerSocket.Write(nsBytes, ex => { if (ex != null) { _logger.LogError(ex, "_producerSocket.Write() | error"); tcs.TrySetException(ex); } }); } catch (Exception ex) { _logger.LogError(ex, "_producerSocket.Write() | error"); tcs.TrySetException(ex); } }); return(tcs.Task); }