77 lines
2.7 KiB
C#
77 lines
2.7 KiB
C#
using Nexus.Api.Models;
|
|
|
|
namespace Nexus.Api.Services;
|
|
|
|
internal static class OpenClawContentReadHelpers
|
|
{
|
|
public const int MaxFiles = 50;
|
|
public const int MaxContentBytes = 1_000_000;
|
|
private const int MaxConcurrency = 4;
|
|
|
|
public static async Task<IReadOnlyList<TResult>> SelectBoundedAsync<TSource, TResult>(
|
|
IEnumerable<TSource> source,
|
|
Func<TSource, CancellationToken, Task<TResult?>> selector,
|
|
CancellationToken cancellationToken)
|
|
where TResult : class
|
|
{
|
|
var items = source.Take(MaxFiles).ToArray();
|
|
var results = new TResult?[items.Length];
|
|
await Parallel.ForEachAsync(
|
|
Enumerable.Range(0, items.Length),
|
|
new ParallelOptions
|
|
{
|
|
CancellationToken = cancellationToken,
|
|
MaxDegreeOfParallelism = MaxConcurrency
|
|
},
|
|
async (index, token) =>
|
|
{
|
|
results[index] = await selector(items[index], token);
|
|
});
|
|
return results.Where(item => item is not null).Select(item => item!).ToArray();
|
|
}
|
|
|
|
public static string? ReadText(OpenClawWorkspaceFileDto file)
|
|
{
|
|
if (file.Size > MaxContentBytes
|
|
|| !string.Equals(file.Encoding, "utf8", StringComparison.OrdinalIgnoreCase)
|
|
|| System.Text.Encoding.UTF8.GetByteCount(file.Content) >
|
|
MaxContentBytes)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return file.Content;
|
|
}
|
|
|
|
public static bool IsMarkdownFile(OpenClawWorkspaceEntryDto entry)
|
|
=> string.Equals(entry.Kind, "file", StringComparison.Ordinal)
|
|
&& entry.Path.EndsWith(".md", StringComparison.OrdinalIgnoreCase)
|
|
&& (entry.Size is null || entry.Size <= MaxContentBytes);
|
|
|
|
public static bool IsNotFound(OpenClawGatewayRpcException exception)
|
|
=> exception.Code.Equals("NOT_FOUND", StringComparison.OrdinalIgnoreCase)
|
|
|| exception.Code.Equals(
|
|
"FILE_NOT_FOUND",
|
|
StringComparison.OrdinalIgnoreCase)
|
|
|| exception.Code.Equals(
|
|
"PATH_NOT_FOUND",
|
|
StringComparison.OrdinalIgnoreCase);
|
|
|
|
public static bool IsSafeFileName(string? value)
|
|
=> !string.IsNullOrWhiteSpace(value)
|
|
&& value.Length <= 240
|
|
&& value is not "." and not ".."
|
|
&& !value.StartsWith('.')
|
|
&& !value.Contains('/')
|
|
&& !value.Contains('\\')
|
|
&& !value.Contains('\0')
|
|
&& !value.Any(char.IsControl);
|
|
|
|
public static string LegacyPath(string workspacePath, string prefix)
|
|
=> workspacePath.StartsWith(
|
|
prefix + "/",
|
|
StringComparison.OrdinalIgnoreCase)
|
|
? workspacePath[(prefix.Length + 1)..]
|
|
: workspacePath;
|
|
}
|