Пример #1
0
        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);
        }
Пример #2
0
        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);
        }