/// <summary>
        /// 开始下载,若获取大小失败,则会抛出异常
        /// </summary>
        public async ValueTask DownloadAsync(CancellationToken token)
        {
            StatusSubject.OnNext(@"正在获取下载文件大小...");
            FileSize = await GetContentLengthAsync(token);             //总大小

            TempDir = EnsureDirectory(TempDir);
            var list = GetFileRangeList();

            var opQueue = new OperationQueue(1);

            Current = 0;
            Last    = 0;
            try
            {
                using var speedMonitor = CreateSpeedMonitor();

                StatusSubject.OnNext(@"正在下载...");
                await list.Select(info =>
                                  // ReSharper disable once AccessToDisposedClosure
                                  opQueue.Enqueue(1, () => GetStreamAsync(info, token))
                                  .ToObservable()
                                  .SelectMany(res => WriteToFileAsync(res.Item1, res.Item2, token))
                                  ).Merge();

                StatusSubject.OnNext(@"下载完成,正在合并文件...");
                Current = 0;
                await MergeFilesAsync(list, token);
            }
            catch (OperationCanceledException)
            {
                StatusSubject.OnNext(@"下载已取消");
                throw;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, @"下载出错");
                StatusSubject.OnNext(@"下载出错");
            }
            finally
            {
                await opQueue.ShutdownQueue();

                opQueue.Dispose();

                Task.Run(async() =>
                {
                    foreach (var range in list)
                    {
                        await DeleteFileWithRetryAsync(range.FileName);
                    }
                }, CancellationToken.None).NoWarning();
            }
        }
        public void Dispose()
        {
            serverConnected.Dispose();
            serverDisconnected.Dispose();
            serverReady.Dispose();
            continueGame.Dispose();
            playersInGameChanged.Dispose();
            gameDisbanded.Dispose();
            gameWillBegin.Dispose();
            gameBegin.Dispose();
            newMessageArrived.Dispose();
            announcementArrived.Dispose();
            beginGameFailed.Dispose();
            invitationArrived.Dispose();

            _queue.Dispose();

            closeConnect();
            GameObject.Destroy(gameObject);
        }