Пример #1
0
        /// <exception cref="InvalidAuthKeyException"/>
        /// <param name="client">要进行请求的 <see cref="HttpClient"/></param>
        /// <param name="options">连接信息</param>
        /// <inheritdoc cref="ExecuteCommandAsync(string, string[], CancellationToken)"/>
        public static async Task ExecuteCommandAsync(HttpClient client, MiraiHttpSessionOptions options, string name, string[]?args, CancellationToken token)
        {
            var payload = new
            {
                authKey = options.AuthKey,
                name,
                args = args ?? Array.Empty <string>()
            };
            string json = await client.PostAsJsonAsync($"{options.BaseUrl}/command/send", payload, token).GetStringAsync(token).ConfigureAwait(false);

            try
            {
                using JsonDocument j = JsonDocument.Parse(json);
                JsonElement root = j.RootElement;
                root.EnsureApiRespCode();
            }
            catch (JsonException) // 返回值非json就是执行失败, 把响应正文重新抛出
            {
                throw new InvalidOperationException(json);
            }
            catch (TargetNotFoundException e) // 指令不存在
            {
                e.ActualMessage = "给定的指令不存在。";
                throw;
            }
        }
Пример #2
0
        /// <param name="client">要进行请求的 <see cref="HttpClient"/></param>
        /// <param name="options">连接信息</param>
        /// <inheritdoc cref="RegisterCommandAsync(string, string[], string, string, CancellationToken)"/>
        public static async Task RegisterCommandAsync(HttpClient client, MiraiHttpSessionOptions options, string name, string[]?alias = null, string?description = null, string?usage = null, CancellationToken token = default)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentException("指令名必须非空。", nameof(name));
            }
            var payload = new
            {
                authKey = options.AuthKey,
                name,
                alias = alias ?? Array.Empty <string>(),
                description,
                usage
            };
            string json = await client.PostAsJsonAsync($"{options.BaseUrl}/command/register", payload, token).GetStringAsync(token).ConfigureAwait(false);

            try
            {
                using JsonDocument j = JsonDocument.Parse(json);
                JsonElement root = j.RootElement;
                root.EnsureApiRespCode();
            }
            catch (JsonException) // 返回值非json就是执行失败, 把响应正文重新抛出
            {
                throw new InvalidOperationException(json);
            }
        }
        private async Task <int> CommonSendMessageAsync(string action, long?qqNumber, long?groupNumber, ISharedChatMessage[] chain, int?quoteMsgId, CancellationToken token = default)
        {
            InternalSessionInfo session = SafeGetSession();

            if (chain == null || chain.Length == 0)
            {
                throw new ArgumentException("消息链必须为非空且至少有1条消息。");
            }
            int emptyPlainCount = 0;

            for (int i = 0; i < chain.Length; i++)
            {
                ISharedChatMessage msg = chain[i];
                if (msg is not IChatMessage)
                {
                    throw new ArgumentException($"不允许发送未实现 {typeof(IChatMessage).FullName} 接口的消息。");
                }
                if (msg is ISourceMessage)
                {
                    throw new ArgumentException("无法发送基本信息(SourceMessage)。");
                }
                if (msg is IQuoteMessage)
                {
                    throw new ArgumentException("无法发送引用信息(QuoteMessage), 请使用quoteMsgId参数进行引用。");
                }
                if (msg is IPlainMessage pm && string.IsNullOrEmpty(pm.Message))
                {
                    emptyPlainCount++;
                }
            }
            if (emptyPlainCount == chain.Length)
            {
                throw new ArgumentException("消息链仅含文本消息且所有文本均为空。");
            }
            // 前边已经检查了所有元素均实现了 IChatMessage 接口, 但直接强制转换数组类型会引发 InvalidCastException, 所以玩一点 trick
            IEnumerable <IChatMessage> convertedChain = Unsafe.As <ISharedChatMessage[], IEnumerable <IChatMessage> >(ref chain);

            CreateLinkedUserSessionToken(session.Token, token, out CancellationTokenSource? cts, out token);
            var payload = new
            {
                sessionKey   = session.SessionKey,
                qq           = qqNumber,
                group        = groupNumber,
                quote        = quoteMsgId,
                messageChain = convertedChain
            };

            using JsonDocument j = await _client.PostAsJsonAsync($"{_options.BaseUrl}/{action}", payload, _chatMessageSerializingOptions, token).GetJsonAsync(token).DisposeWhenCompleted(cts).ConfigureAwait(false);

            JsonElement root = j.RootElement;

            root.EnsureApiRespCode();
            return(root.GetProperty("messageId").GetInt32());
        }
Пример #4
0
        /// <param name="client">要进行请求的 <see cref="HttpClient"/></param>
        /// <param name="options">连接信息</param>
        /// <inheritdoc cref="GetVersionAsync(CancellationToken)"/>
        public static async Task <Version> GetVersionAsync(HttpClient client, MiraiHttpSessionOptions options, CancellationToken token = default)
        {
            using JsonDocument j = await client.GetAsync($"{options.BaseUrl}/about", token).GetJsonAsync(token).ConfigureAwait(false);

            JsonElement root = j.RootElement;

            root.EnsureApiRespCode();
            string version = root.GetProperty("data").GetProperty("version").GetString() !;
            int    vIndex  = version.IndexOf('v');

#if NETSTANDARD2_0
            return(Version.Parse(vIndex != -1 ? version.Substring(vIndex) : version));        // v1.0.0 ~ v1.7.4, skip 'v'
#else
            return(Version.Parse(vIndex != -1 ? version.AsSpan()[(vIndex + 1)..] : version)); // v1.0.0 ~ v1.7.4, skip 'v'
Пример #5
0
        /// <inheritdoc/>
        /// <remarks>
        /// 当缓存失效, 或者未注册用于解析消息的 <see cref="IMiraiHttpMessageParser{TMessage}"/> 时, 本异步方法将返回 <see langword="null"/>
        /// </remarks>
        public async Task <IMiraiHttpMessage?> RetriveMessageAsync(int messageId, CancellationToken token = default)
        {
            InternalSessionInfo             session  = SafeGetSession();
            IMiraiHttpMessageParserResolver resolver = _services.GetRequiredService <IMiraiHttpMessageParserResolver>();

            CreateLinkedUserSessionToken(session.Token, token, out CancellationTokenSource? cts, out token);
            JsonElement root = await _client.GetAsync($"{_options.BaseUrl}/messageFromId?sessionKey={session.SessionKey}&id={messageId}", token)
                               .GetObjectAsync <JsonElement>(token)
                               .DisposeWhenCompleted(cts);

            root.EnsureApiRespCode();
            JsonElement             data   = root.GetProperty("data");
            IMiraiHttpMessageParser?parser = resolver.ResolveParser(in data);

            if (parser != null && parser.CanParse(in data))
            {
                return((IMiraiHttpMessage)parser.Parse(in data));
            }
            return(null);
        }
Пример #6
0
        private static async Task <string> AuthorizeAsync(HttpClient client, MiraiHttpSessionOptions options, Version apiVersion, CancellationToken token = default)
        {
            //https://github.com/project-mirai/mirai-api-http/blob/master/docs/misc/Migration2.md#%E8%AE%A4%E8%AF%81%E6%B5%81%E7%A8%8B
            string           url;
            AuthorizePayload payload;

            if (apiVersion.Major >= 2)
            {
                url     = $"{options.BaseUrl}/verify";
                payload = new AuthorizePayloadv2(options.AuthKey);
            }
            else
            {
                url     = $"{options.BaseUrl}/auth";
                payload = new AuthorizePayloadv1(options.AuthKey);
            };
            using JsonDocument j = await client.PostAsJsonAsync <object>(url, payload, token).GetJsonAsync(token).ConfigureAwait(false);

            JsonElement root = j.RootElement;

            root.EnsureApiRespCode();
            return(root.GetProperty("session").GetString() !);
        }