Beispiel #1
0
 private Task SetConfigAsync(InternalSessionInfo session, IMiraiSessionConfig config)
 {
     byte[] payload = JsonSerializer.SerializeToUtf8Bytes(new
     {
         sessionKey      = session.SessionKey,
         cacheSize       = config.CacheSize,
         enableWebsocket = config.EnableWebSocket
     }, JsonSerializeOptionsFactory.IgnoreNulls);
     return(InternalHttpPostAsync($"{session.Options.BaseUrl}/config", payload, session.Canceller.Token));
 }
Beispiel #2
0
        /// <inheritdoc/>
        public Task SetConfigAsync(IMiraiSessionConfig config, CancellationToken token = default)
        {
            InternalSessionInfo session = SafeGetSession();

            if (session.ApiVersion.Major >= 2)
            {
                throw new NotSupportedException("自 mirai-api-http v2.0.0 起, 本接口不受支持");
            }
            CreateLinkedUserSessionToken(session.Token, token, out CancellationTokenSource? cts, out token);
            return(SetConfigAsync(session, config, token).DisposeWhenCompleted(cts));
        }
Beispiel #3
0
        private Task SetConfigAsync(InternalSessionInfo session, IMiraiSessionConfig config, CancellationToken token = default)
        {
            var payload = new
            {
                sessionKey      = session.SessionKey,
                cacheSize       = config.CacheSize,
                enableWebsocket = config.EnableWebSocket
            };

            return(_client.PostAsJsonAsync($"{_options.BaseUrl}/config", payload, JsonSerializeOptionsFactory.IgnoreNulls, session.Token).AsApiRespAsync(session.Token));
        }
        /// <summary>
        /// 异步连接到mirai-api-http。
        /// </summary>
        /// <remarks>
        /// 此方法线程安全。但是在连接过程中, 如果尝试多次调用, 除了第一次以后的所有调用都将立即返回。
        /// </remarks>
        /// <exception cref="BotNotFoundException"/>
        /// <exception cref="InvalidAuthKeyException"/>
        /// <param name="options">连接信息</param>
        /// <param name="qqNumber">Session将要绑定的Bot的qq号</param>
        /// <param name="listenCommand">是否监听指令相关的消息</param>
        public async Task ConnectAsync(MiraiHttpSessionOptions options, long qqNumber, bool listenCommand)
        {
            CheckDisposed();
            InternalSessionInfo session = new InternalSessionInfo();

            if (Interlocked.CompareExchange(ref SessionInfo, session, null !) == null)
            {
                try
                {
                    session.Client     = new HttpClient();
                    session.SessionKey = await AuthorizeAsync(session.Client, options);

                    session.Options = options;
                    await VerifyAsync(session.Client, options, session.SessionKey, qqNumber);

                    session.QQNumber   = qqNumber;
                    session.ApiVersion = await GetVersionAsync(session.Client, options);

                    CancellationTokenSource canceller = new CancellationTokenSource();
                    session.Canceller = canceller;
                    session.Token     = canceller.Token;
                    session.Connected = true;
                    IMiraiSessionConfig config = await this.GetConfigAsync(session);

                    if (!config.EnableWebSocket.GetValueOrDefault())
                    {
                        await this.SetConfigAsync(session, new MiraiSessionConfig { CacheSize = config.CacheSize, EnableWebSocket = true });
                    }
                    CancellationToken token = session.Canceller.Token;
                    ReceiveMessageLoop(session, token);
                    if (listenCommand)
                    {
                        ReceiveCommandLoop(session, token);
                    }
                }
                catch
                {
                    Interlocked.CompareExchange(ref SessionInfo, null, session);
                    _ = InternalReleaseAsync(session);
                    throw;
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// 异步连接到mirai-api-http。
        /// </summary>
        /// <remarks>
        /// 此方法不是线程安全的。
        /// </remarks>
        /// <exception cref="BotNotFoundException"/>
        /// <exception cref="InvalidAuthKeyException"/>
        /// <param name="options">连接信息</param>
        /// <param name="qqNumber">Session将要绑定的Bot的qq号</param>
        /// <param name="listenCommand">是否监听指令相关的消息</param>
        public async Task ConnectAsync(MiraiHttpSessionOptions options, long qqNumber, bool listenCommand)
        {
            CheckDisposed();
            if (this.Connected)
            {
                return;
            }
            string sessionKey = await AuthorizeAsync(options);

            await VerifyAsync(options, sessionKey, qqNumber);

            ApiVersion = await GetVersionAsync(options);

            InternalSessionInfo session = new InternalSessionInfo
            {
                Options    = options,
                SessionKey = sessionKey,
                QQNumber   = qqNumber,
                Canceller  = new CancellationTokenSource()
            };

            try
            {
                IMiraiSessionConfig config = await this.GetConfigAsync(session);

                if (!config.EnableWebSocket.GetValueOrDefault())
                {
                    await this.SetConfigAsync(session, new MiraiSessionConfig { CacheSize = config.CacheSize, EnableWebSocket = true });
                }
                CancellationToken token = session.Canceller.Token;
                ReceiveMessageLoop(session, token);
                if (listenCommand)
                {
                    ReceiveCommandLoop(session, token);
                }
                SessionInfo = session;
            }
            catch // 如果这都报错那真是见了鬼了
            {
                _ = InternalReleaseAsync(session);
                throw;
            }
        }
Beispiel #6
0
 /// <summary>
 /// 异步设置当前Session的Config
 /// </summary>
 /// <param name="config">配置信息</param>
 public Task SetConfigAsync(IMiraiSessionConfig config)
 {
     CheckConnected();
     return(SetConfigAsync(SessionInfo, config));
 }
Beispiel #7
0
        /// <inheritdoc/>
        public async Task ConnectAsync(long qqNumber, bool listenCommand, CancellationToken token = default)
        {
            CancellationTokenSource?instanceCts   = Volatile.Read(ref _instanceCts);
            CancellationToken       instanceToken = instanceCts?.Token ?? throw new ObjectDisposedException(this.GetType().Name);
            CancellationToken       createdToken;
            InternalSessionInfo?    previousSession = Volatile.Read(ref _currentSession);
            InternalSessionInfo?    createdSession  = null;

            if (previousSession != null ||
                Interlocked.CompareExchange(ref _currentSession, createdSession = new InternalSessionInfo(instanceToken), null) != null)
            {
                createdSession?.Dispose();
                throw new InvalidOperationException();
            }
            createdToken = createdSession.Token;
            using CancellationTokenSource tempCts = CancellationTokenSource.CreateLinkedTokenSource(createdToken, token);
            CancellationToken tempToken = tempCts.Token;

            try
            {
                Version apiVersion = await GetVersionAsync(_client, _options, tempToken).ConfigureAwait(false);

                createdSession.ApiVersion = apiVersion;
                createdSession.QQNumber   = qqNumber;
                createdSession.SessionKey = await AuthorizeAsync(_client, _options, apiVersion, tempToken).ConfigureAwait(false);
                await VerifyAsync(_client, _options, apiVersion, createdSession, tempToken).ConfigureAwait(false);

                bool v1 = apiVersion.Major < 2;
                if (v1)
                {
                    IMiraiSessionConfig config = await this.GetConfigAsync(createdSession, tempToken).ConfigureAwait(false);

                    if (!config.EnableWebSocket.GetValueOrDefault())
                    {
                        await this.SetConfigAsync(createdSession, new MiraiSessionConfig { CacheSize = config.CacheSize, EnableWebSocket = true }, tempToken).ConfigureAwait(false);
                    }
                }
                Task t1 = StartReceiveMessageLoopAsync(_options, createdSession, tempToken, createdToken);
                // mirai-api-http v2.0起, 指令ws合并进all, 所以只需连接上边这个就可以了
                Task t2 = v1 && listenCommand?StartReceiveCommandLoopAsync(_options, createdSession, tempToken, createdToken) : Task.CompletedTask;

                await Task.WhenAll(t1, t2).ConfigureAwait(false);

                createdSession.Connected = true;
            }
            catch
            {
                if (Interlocked.CompareExchange(ref _currentSession, null !, createdSession) == createdSession) // 避免 StartReceiveMessageLoopAsync 和
                                                                                                                // StartReceiveCommandLoopAsync 中间出现连接断开
                                                                                                                // 导致释放两次 session
                {
                    tempCts.Cancel();
                    createdSession.Dispose();
                    if (createdSession.SessionKey != null)
                    {
                        _ = InternalReleaseAsync(createdSession.SessionKey, qqNumber, instanceToken);
                    }
                }
                throw;
            }
        }
Beispiel #8
0
        /// <summary>
        /// 异步设置当前Session的Config
        /// </summary>
        /// <param name="config">配置信息</param>
        public Task SetConfigAsync(IMiraiSessionConfig config)
        {
            InternalSessionInfo session = SafeGetSession();

            return(SetConfigAsync(session, config));
        }