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 ns = NetstringWriter.Encode(requestMesssge.ToCamelCaseJson()); var bytes = Encoding.UTF8.GetBytes(ns); if (bytes.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(ns, 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); }
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); }