Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@
<PackageVersion Include="AspNet.Security.OAuth.Kook" Version="10.0.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
<PackageVersion Include="Fluid.Core" Version="2.31.0" />
<PackageVersion Include="MassTransit" Version="8.5.5" />
<PackageVersion Include="MassTransit" Version="[8.5.8, 9)" />
<PackageVersion Include="MassTransit.Extensions.DependencyInjection" Version="7.3.1" />
Comment thread
gehongyan marked this conversation as resolved.
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.0" />
<PackageVersion Include="Meziantou.Polyfill" Version="1.0.101" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.3" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.3" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.103" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="PolySharp" Version="1.15.0" />
<PackageVersion Include="Serilog" Version="4.3.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="9.0.0" />
<PackageVersion Include="Serilog" Version="4.3.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="System.Collections.Immutable" Version="10.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.3" />
<PackageVersion Include="System.Text.Json" Version="10.0.0" />
<PackageVersion Include="System.Collections.Immutable" Version="10.0.3" />
<PackageVersion Include="System.Linq.Async" Version="7.0.0" />
<PackageVersion Include="System.Text.Json" Version="10.0.3" />
<PackageVersion Include="System.Threading.Channels" Version="10.0.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="xunit.v3" Version="3.2.0" />
Expand Down
57 changes: 32 additions & 25 deletions THIRD-PARTY-NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,38 @@ Licensed under the Apache License, Version 2.0.
Available at
https://github.com/MassTransit/MassTransit/blob/develop/LICENSE

License notice for MassTransit.Extensions.Hosting
------------------------------------

Licensed under the Apache License, Version 2.0.
Available at
https://github.com/NCodeGroup/MassTransit.Extensions.Hosting/blob/master/LICENSE.txt

License notice for Meziantou.Polyfill
------------------------------------

MIT License

Copyright (c) Gérald Barré

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

License notice for Microsoft.NET.Test.Sdk
------------------------------------

Expand Down Expand Up @@ -187,31 +219,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

[ https://www.opensource.org/licenses/bsd-license.php ]

License notice for PolySharp
------------------------------------

MIT License

Copyright (c) 2022 Sergio Pedri

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

License notice for Serilog
------------------------------------

Expand Down
28 changes: 17 additions & 11 deletions props/common.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<PackageReleaseNotes>See https://github.com/gehongyan/Kook.Net/releases</PackageReleaseNotes>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo_Small.png</PackageIcon>
<TargetFrameworks>net10.0;net9.0;net8.0;net462;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>net10.0;net9.0;net8.0;net462;netstandard2.1;netstandard2.0</TargetFrameworks>
Comment thread
gehongyan marked this conversation as resolved.
<NoWarn>$(NoWarn);NU1803;NU1900</NoWarn>
<WarningLevel>6</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand All @@ -35,25 +35,31 @@
<Version Condition=" '$(VersionSuffix)' == '' ">$(VersionPrefix)</Version>
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix)-$(VersionSuffix)</Version>
</PropertyGroup>
<PropertyGroup>
<DefineConstants Condition="!('$(TargetFramework)' == 'netstandard2.0' OR $(TargetFramework.StartsWith('net4')))">$(DefineConstants);SUPPORTS_ASYNC_DISPOSABLE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) AND '$(MSBuildRuntimeType)' == 'Core' AND '$(OS)' != 'Windows_NT'">
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" PrivateAssets="All" />
</ItemGroup>
<ItemGroup Condition=" !$(TargetFramework.StartsWith('net10.0')) ">
<PackageReference Include="PolySharp">
<ItemGroup>
<PackageReference Include="Meziantou.Polyfill">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net4'))">
<Reference Include="System.Net.Http"/>
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) AND '$(MSBuildRuntimeType)' == 'Core' AND '$(OS)' != 'Windows_NT'">
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" PrivateAssets="All"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All"/>
</ItemGroup>
<ItemGroup>
<None Include="../../README.md" Pack="true" PackagePath="\" />
<None Include="../../LICENSE" Pack="true" PackagePath="\" />
<None Include="../../THIRD-PARTY-NOTICES.md" Pack="true" PackagePath="\" />
<None Include="../../docs/logo/Logo_Small.png" Pack="true" PackagePath="" />
<None Include="../../README.md" Pack="true" PackagePath="\"/>
<None Include="../../LICENSE" Pack="true" PackagePath="\"/>
<None Include="../../THIRD-PARTY-NOTICES.md" Pack="true" PackagePath="\"/>
<None Include="../../docs/logo/Logo_Small.png" Pack="true" PackagePath=""/>
</ItemGroup>
</Project>
7 changes: 3 additions & 4 deletions src/Kook.Net.CardMarkup/CardMarkupSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ public static class CardMarkupSerializer
/// <returns> 一个表示异步解析操作的任务。任务的结果包含一个可用于枚举 <see cref="ICard"/> 成员的 <see cref="System.Collections.Generic.IEnumerable{T}"/>。 </returns>
public static async Task<IEnumerable<ICard>> DeserializeAsync(FileInfo file, CancellationToken token = default)
{
#if NETSTANDARD2_0 || NET462
using FileStream fs = file.OpenRead();
#else
await using FileStream fs = file.OpenRead();
#if SUPPORTS_ASYNC_DISPOSABLE
await
#endif
using FileStream fs = file.OpenRead();
return await DeserializeAsync(fs, token);
}

Expand Down
4 changes: 0 additions & 4 deletions src/Kook.Net.Commands/Map/CommandMapNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ internal class CommandMapNode

private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;
private readonly string _name;
#if NET9_0_OR_GREATER
private readonly Lock _lockObj = new();
#else
private readonly object _lockObj = new();
#endif
private ImmutableArray<CommandInfo> _commands;

// ReSharper disable InconsistentlySynchronizedField
Expand Down
2 changes: 1 addition & 1 deletion src/Kook.Net.Commands/PrimitiveParsers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ private static IReadOnlyDictionary<Type, Delegate> CreateParsers()
parserBuilder[typeof(DateTime)] = (TryParseDelegate<DateTime>)DateTime.TryParse;
parserBuilder[typeof(DateTimeOffset)] = (TryParseDelegate<DateTimeOffset>)DateTimeOffset.TryParse;
parserBuilder[typeof(Guid)] = (TryParseDelegate<Guid>)Guid.TryParse;
#if NET6_0_OR_GREATER
#if NET
Comment thread
gehongyan marked this conversation as resolved.
parserBuilder[typeof(DateOnly)] = (TryParseDelegate<DateOnly>)DateOnly.TryParse;
parserBuilder[typeof(TimeOnly)] = (TryParseDelegate<TimeOnly>)TimeOnly.TryParse;
#endif
Expand Down
137 changes: 97 additions & 40 deletions src/Kook.Net.Core/Extensions/CollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,61 +5,118 @@ namespace Kook;

internal static class CollectionExtensions
{
//public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TValue>(this IReadOnlyCollection<TValue> source)
// => new CollectionWrapper<TValue>(source, () => source.Count);
// extension<TValue>(IReadOnlyCollection<TValue> source)
// {
// public IReadOnlyCollection<TValue> ToReadOnlyCollection()
// => new CollectionWrapper<TValue>(source, () => source.Count);
// }

public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TValue>(this ICollection<TValue> source) =>
new CollectionWrapper<TValue>(source, () => source.Count);
extension<TValue>(ICollection<TValue> source)
{
public IReadOnlyCollection<TValue> ToReadOnlyCollection() =>
new CollectionWrapper<TValue>(source, () => source.Count);
}

// extension<TKey, TValue>(IReadOnlyDictionary<TKey, TValue> source)
// {
// public IReadOnlyCollection<TValue> ToReadOnlyCollection()
// => new CollectionWrapper<TValue>(source.Select(x => x.Value), () => source.Count);
// }

extension<TKey, TValue>(IDictionary<TKey, TValue> source)
{
public IReadOnlyCollection<TValue> ToReadOnlyCollection() =>
new CollectionWrapper<TValue>(source.Values, () => source.Count);
}

extension<TValue>(IEnumerable<TValue> query)
{
public IReadOnlyCollection<TValue> ToReadOnlyCollection<TSource>(IReadOnlyCollection<TSource> source) =>
new CollectionWrapper<TValue>(query, () => source.Count);

public IReadOnlyCollection<TValue> ToReadOnlyCollection(Func<int> countFunc) =>
new CollectionWrapper<TValue>(query, countFunc);

//public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source)
// => new CollectionWrapper<TValue>(source.Select(x => x.Value), () => source.Count);
#if NETSTANDARD || NETFRAMEWORK
public IEnumerable<TValue[]> Chunk(int size)
{
if (query is null)
throw new ArgumentNullException(nameof(query));

public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TKey, TValue>(this IDictionary<TKey, TValue> source) =>
new CollectionWrapper<TValue>(source.Values, () => source.Count);
if (size <= 0)
throw new ArgumentOutOfRangeException(nameof(size));

public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TValue, TSource>(this IEnumerable<TValue> query,
IReadOnlyCollection<TSource> source) =>
new CollectionWrapper<TValue>(query, () => source.Count);
return ChunkIterator(query, size);

public static IReadOnlyCollection<TValue> ToReadOnlyCollection<TValue>(this IEnumerable<TValue> query, Func<int> countFunc) =>
new CollectionWrapper<TValue>(query, countFunc);
static IEnumerable<TValue[]> ChunkIterator(IEnumerable<TValue> source, int size)
{
using IEnumerator<TValue> e = source.GetEnumerator();

#if !NET6_0_OR_GREATER
public static TSource? MinBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector) =>
source.OrderBy(keySelector).FirstOrDefault();
// Before allocating anything, make sure there's at least one element.
if (e.MoveNext())
{
// Now that we know we have at least one item, allocate an initial storage array. This is not
// the array we'll yield. It starts out small in order to avoid significantly overallocating
// when the source has many fewer elements than the chunk size.
int arraySize = Math.Min(size, 4);
int i;
do
{
TValue[]? array = new TValue[arraySize];

public static TSource? MaxBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector) =>
source.OrderByDescending(keySelector).FirstOrDefault();
// Store the first item.
array[0] = e.Current;
i = 1;

public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize) =>
source
.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / chunkSize)
.Select(x => x.Select(v => v.Value));
if (size != array.Length)
{
// This is the first chunk. As we fill the array, grow it as needed.
for (; i < size && e.MoveNext(); i++)
{
if (i >= array.Length)
{
arraySize = (int)Math.Min((uint)size, 2 * (uint)array.Length);
Array.Resize(ref array, arraySize);
}

array[i] = e.Current;
}
}
else
{
// For all but the first chunk, the array will already be correctly sized.
// We can just store into it until either it's full or MoveNext returns false.
TValue[] local = array; // avoid bounds checks by using cached local (`array` is lifted to iterator object as a field)
for (; (uint)i < (uint)local.Length && e.MoveNext(); i++)
{
local[i] = e.Current;
}
}

if (i != array.Length)
{
Array.Resize(ref array, i);
}

yield return array;
}
while (i >= size && e.MoveNext());
}
}
}
#endif
}
}

[DebuggerDisplay("{DebuggerDisplay,nq}")]
internal readonly struct CollectionWrapper<TValue> : IReadOnlyCollection<TValue>
internal readonly struct CollectionWrapper<TValue>
(IEnumerable<TValue> query, Func<int> countFunc) : IReadOnlyCollection<TValue>
{
private readonly IEnumerable<TValue> _query;
private readonly Func<int> _countFunc;

//It's okay that this count is affected by race conditions - we're wrapping a concurrent collection and that's to be expected
public int Count => _countFunc();

public CollectionWrapper(IEnumerable<TValue> query, Func<int> countFunc)
{
_query = query;
_countFunc = countFunc;
}
public int Count => countFunc();

private string DebuggerDisplay => $"Count = {Count}";

public IEnumerator<TValue> GetEnumerator() => _query.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _query.GetEnumerator();
public IEnumerator<TValue> GetEnumerator() => query.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => query.GetEnumerator();
}
3 changes: 3 additions & 0 deletions src/Kook.Net.Core/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#if NETFRAMEWORK
global using System.Net.Http;
#endif
18 changes: 17 additions & 1 deletion src/Kook.Net.Core/Kook.Net.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,26 @@
<Description>The core definition library for Kook.Net.</Description>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="System.Collections.Immutable" />
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Collections.Immutable" />
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="System.Collections.Immutable" />
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>
<ItemGroup Condition=" !$(TargetFramework.StartsWith('net10.0')) ">
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="System.Linq.Async" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
<PackageReference Include="System.Linq.Async" />
</ItemGroup>

Copilot AI Feb 14, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package references have been reorganized to be framework-specific, but there's no ItemGroup for net10.0. Given that net10.0 is in the target frameworks list (line 25 in common.props), net10.0 builds will not get any of these package references. If net10.0 has System.Linq.Async built-in or doesn't need it, this is fine. Otherwise, add an ItemGroup condition for net10.0 or verify that the packages are not needed for this target framework.

Suggested change
</ItemGroup>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net10.0'">
<PackageReference Include="System.Linq.Async" />
</ItemGroup>

Copilot uses AI. Check for mistakes.
</Project>
3 changes: 0 additions & 3 deletions src/Kook.Net.Core/Net/BucketId.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System.Diagnostics.CodeAnalysis;
#if NET462
using System.Net.Http;
#endif

namespace Kook.Net;

Expand Down
Loading