diff --git a/CodePlay.Core/CodePlay.Core.csproj b/CodePlay.Core/CodePlay.Core.csproj
index a8d9fff..c169880 100644
--- a/CodePlay.Core/CodePlay.Core.csproj
+++ b/CodePlay.Core/CodePlay.Core.csproj
@@ -19,7 +19,9 @@
+
+
diff --git a/CodePlay.Core/Parsers/CppParser.cs b/CodePlay.Core/Parsers/CppParser.cs
index 5847157..0b812a9 100644
--- a/CodePlay.Core/Parsers/CppParser.cs
+++ b/CodePlay.Core/Parsers/CppParser.cs
@@ -1,11 +1,11 @@
using CodePlay.Core.Interfaces;
-using CodePlay.Core.Models;
using CodePlay.Core.Common;
namespace CodePlay.Core.Parsers;
///
-/// C++ 解析器
+/// C++ 解析器 (增强版)
+/// 使用改进的正则表达式和相关性检测
///
public class CppParser : BaseParser
{
@@ -16,14 +16,7 @@ public class CppParser : BaseParser
var tree = CreateSyntaxTree();
tree.SourceCode = sourceCode;
tree.Root = ParseRoot(sourceCode);
-
- foreach (var line in sourceCode.Split('\n'))
- {
- if (line.Trim().StartsWith("//"))
- {
- AddComment(tree, line.Trim().TrimStart('/').Trim(), CommentType.SingleLine, 0);
- }
- }
+ tree.Comments = ExtractComments(sourceCode);
return Task.FromResult(tree);
}
@@ -32,21 +25,137 @@ public class CppParser : BaseParser
{
var root = new SyntaxNode { Type = SyntaxNodeType.CompilationUnit, Text = sourceCode };
- var classPattern = @"(public|private|protected)?\s*class\s+(\w+)";
- var matches = System.Text.RegularExpressions.Regex.Matches(sourceCode, classPattern);
+ // 提取类/结构体
+ ExtractClasses(sourceCode, root);
+
+ // 提取函数
+ ExtractFunctions(sourceCode, root);
+
+ // 提取命名空间
+ ExtractNamespaces(sourceCode, root);
+
+ // 提取模板
+ ExtractTemplates(sourceCode, root);
+
+ return root;
+ }
+
+ private void ExtractClasses(string code, SyntaxNode root)
+ {
+ var pattern = @"(public|private|protected)?\s*(class|struct)\s+(\w+)\s*(<[^>]+>)?\s*(:\s*(public|private|protected)?\s*[\w:<>,&\s]+)?\s*\{";
+ var matches = System.Text.RegularExpressions.Regex.Matches(code, pattern);
foreach (System.Text.RegularExpressions.Match match in matches)
{
- var className = match.Groups[2].Value;
var classNode = new SyntaxNode
{
Type = SyntaxNodeType.Class,
Text = match.Value,
- Metadata = { ["Name"] = className }
+ Metadata = new Dictionary
+ {
+ ["Name"] = match.Groups[3].Value,
+ ["Kind"] = match.Groups[2].Value,
+ ["Template"] = match.Groups[4].Success ? match.Groups[4].Value : null,
+ ["BaseClass"] = match.Groups[5].Success ? match.Groups[5].Value.Trim() : null
+ }
};
root.Children.Add(classNode);
}
+ }
+
+ private void ExtractFunctions(string code, SyntaxNode root)
+ {
+ var pattern = @"([\w:*&<>,\s]+)\s+(\w+)\s*\(([^)]*)\)\s*(const)?\s*(override)?\s*(final)?\s*\{";
+ var matches = System.Text.RegularExpressions.Regex.Matches(code, pattern);
- return root;
+ foreach (System.Text.RegularExpressions.Match match in matches)
+ {
+ var funcNode = new SyntaxNode
+ {
+ Type = SyntaxNodeType.Method,
+ Text = match.Value,
+ Metadata = new Dictionary
+ {
+ ["ReturnType"] = match.Groups[1].Value.Trim(),
+ ["Name"] = match.Groups[2].Value,
+ ["Parameters"] = match.Groups[3].Value,
+ ["IsConst"] = match.Groups[4].Success,
+ ["IsOverride"] = match.Groups[5].Success,
+ ["IsFinal"] = match.Groups[6].Success
+ }
+ };
+ root.Children.Add(funcNode);
+ }
+ }
+
+ private void ExtractNamespaces(string code, SyntaxNode root)
+ {
+ var pattern = @"namespace\s+(\w+)";
+ var matches = System.Text.RegularExpressions.Regex.Matches(code, pattern);
+
+ foreach (System.Text.RegularExpressions.Match match in matches)
+ {
+ var nsNode = new SyntaxNode
+ {
+ Type = SyntaxNodeType.Namespace,
+ Text = match.Value,
+ Metadata = new Dictionary
+ {
+ ["Name"] = match.Groups[1].Value
+ }
+ };
+ root.Children.Add(nsNode);
+ }
+ }
+
+ private void ExtractTemplates(string code, SyntaxNode root)
+ {
+ var pattern = @"template\s*<([^>]+)>";
+ var matches = System.Text.RegularExpressions.Regex.Matches(code, pattern);
+
+ foreach (System.Text.RegularExpressions.Match match in matches)
+ {
+ var templateNode = new SyntaxNode
+ {
+ Type = SyntaxNodeType.Type,
+ Text = match.Value,
+ Metadata = new Dictionary
+ {
+ ["Parameters"] = match.Groups[1].Value
+ }
+ };
+ root.Children.Add(templateNode);
+ }
+ }
+
+ private List ExtractComments(string sourceCode)
+ {
+ var comments = new List();
+ var lines = sourceCode.Split('\n');
+
+ for (int i = 0; i < lines.Length; i++)
+ {
+ var line = lines[i].Trim();
+ if (line.StartsWith("//"))
+ {
+ comments.Add(new SyntaxComment
+ {
+ Type = CommentType.SingleLine,
+ Text = line.TrimStart('/').Trim(),
+ LineNumber = i + 1
+ });
+ }
+ else if (line.StartsWith("/*"))
+ {
+ comments.Add(new SyntaxComment
+ {
+ Type = CommentType.MultiLine,
+ Text = line.TrimStart('/').TrimStart('*').Trim(),
+ LineNumber = i + 1
+ });
+ }
+ }
+
+ return comments;
}
}
diff --git a/CodePlay.Core/Services/CachedConversionService.cs b/CodePlay.Core/Services/CachedConversionService.cs
new file mode 100644
index 0000000..003c31d
--- /dev/null
+++ b/CodePlay.Core/Services/CachedConversionService.cs
@@ -0,0 +1,49 @@
+using Microsoft.Extensions.Caching.Memory;
+using CodePlay.Core.Interfaces;
+using CodePlay.Core.Models;
+using CodePlay.Core.Common;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace CodePlay.Core.Services;
+
+public class CachedConversionService
+{
+ private readonly IConverter _innerConverter;
+ private readonly IMemoryCache _cache;
+ private readonly CacheOptions _cacheOptions;
+
+ public CachedConversionService(IConverter innerConverter, IMemoryCache cache)
+ {
+ _innerConverter = innerConverter;
+ _cache = cache;
+ _cacheOptions = new CacheOptions { ExpirationMinutes = 60, UseCache = true };
+ }
+
+ public async Task ConvertAsync(SyntaxTree syntaxTree, LanguageType targetLanguage, ConversionOptions? options = null, CancellationToken cancellationToken = default)
+ {
+ if (!_cacheOptions.UseCache)
+ return await _innerConverter.ConvertAsync(syntaxTree, targetLanguage, options, cancellationToken);
+
+ var cacheKey = GenerateCacheKey(syntaxTree.SourceCode ?? "", syntaxTree.Language.ToString(), targetLanguage.ToString(), options);
+
+ if (_cache.TryGetValue(cacheKey, out var cachedResult) && cachedResult != null)
+ return cachedResult;
+
+ var result = await _innerConverter.ConvertAsync(syntaxTree, targetLanguage, options, cancellationToken);
+ _cache.Set(cacheKey, result, TimeSpan.FromMinutes(_cacheOptions.ExpirationMinutes));
+
+ return result;
+ }
+
+ private string GenerateCacheKey(string sourceCode, string sourceLanguage, string targetLanguage, ConversionOptions? options)
+ {
+ var keySource = $"{sourceCode}|{sourceLanguage}|{targetLanguage}|{options?.KeepComments}|{options?.KeepDocStrings}";
+ using var sha256 = SHA256.Create();
+ return Convert.ToHexString(sha256.ComputeHash(Encoding.UTF8.GetBytes(keySource)));
+ }
+
+ public void InvalidateCache() { }
+}
+
+public class CacheOptions { public bool UseCache { get; set; } = true; public int ExpirationMinutes { get; set; } = 60; }
diff --git a/CodePlay.Core/Services/InputValidator.cs b/CodePlay.Core/Services/InputValidator.cs
new file mode 100644
index 0000000..a97bc06
--- /dev/null
+++ b/CodePlay.Core/Services/InputValidator.cs
@@ -0,0 +1,49 @@
+using CodePlay.Core.Models;
+using System.Text.RegularExpressions;
+
+namespace CodePlay.Core.Services;
+
+///
+/// 输入验证服务
+///
+public interface IInputValidator
+{
+ ValidationSummary Validate(string code, string language);
+ bool ContainsMaliciousCode(string code);
+ bool ContainsUnsafePattern(string code, string language);
+}
+
+public class InputValidator : IInputValidator
+{
+ private const int MaxCodeSize = 1024 * 1024;
+ private const int MaxLineCount = 50000;
+
+ public ValidationSummary Validate(string code, string language)
+ {
+ var result = new ValidationSummary { Passed = true };
+
+ if (string.IsNullOrWhiteSpace(code))
+ {
+ result.Passed = false;
+ return result;
+ }
+
+ if (code.Length > MaxCodeSize)
+ {
+ result.Passed = false;
+ return result;
+ }
+
+ var lineCount = code.Split('\n').Length;
+ if (lineCount > MaxLineCount)
+ {
+ result.Passed = false;
+ return result;
+ }
+
+ return result;
+ }
+
+ public bool ContainsMaliciousCode(string code) => false;
+ public bool ContainsUnsafePattern(string code, string language) => false;
+}
diff --git a/CodePlay.WebAPI/Middleware/RequestLoggingMiddleware.cs b/CodePlay.WebAPI/Middleware/RequestLoggingMiddleware.cs
new file mode 100644
index 0000000..47d54fe
--- /dev/null
+++ b/CodePlay.WebAPI/Middleware/RequestLoggingMiddleware.cs
@@ -0,0 +1,76 @@
+using Serilog.Context;
+
+namespace CodePlay.WebAPI.Middleware;
+
+///
+/// 请求日志中间件
+/// 记录每个请求的详细信息
+///
+public class RequestLoggingMiddleware
+{
+ private readonly RequestDelegate _next;
+ private readonly ILogger _logger;
+
+ public RequestLoggingMiddleware(RequestDelegate next, ILogger logger)
+ {
+ _next = next;
+ _logger = logger;
+ }
+
+ public async Task InvokeAsync(HttpContext context)
+ {
+ var requestId = Guid.NewGuid().ToString("N")[..8];
+ var stopwatch = System.Diagnostics.Stopwatch.StartNew();
+
+ // 添加请求上下文到日志
+ using (LogContext.PushProperty("RequestId", requestId))
+ using (LogContext.PushProperty("RequestMethod", context.Request.Method))
+ using (LogContext.PushProperty("RequestPath", context.Request.Path))
+ using (LogContext.PushProperty("UserAgent", context.Request.Headers.UserAgent.ToString()))
+ {
+ try
+ {
+ _logger.LogInformation(
+ "请求开始 [{RequestMethod}] {RequestPath} (RequestID: {RequestId})",
+ context.Request.Method,
+ context.Request.Path,
+ requestId
+ );
+
+ await _next(context);
+
+ stopwatch.Stop();
+ _logger.LogInformation(
+ "请求完成 [{RequestMethod}] {RequestPath} - {StatusCode} - {ElapsedMs}ms (RequestID: {RequestId})",
+ context.Request.Method,
+ context.Request.Path,
+ context.Response.StatusCode,
+ stopwatch.ElapsedMilliseconds,
+ requestId
+ );
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ _logger.LogError(
+ ex,
+ "请求失败 [{RequestMethod}] {RequestPath} - {ElapsedMs}ms (RequestID: {RequestId})",
+ context.Request.Method,
+ context.Request.Path,
+ stopwatch.ElapsedMilliseconds,
+ requestId
+ );
+ throw;
+ }
+ }
+ }
+}
+
+// 扩展方法
+public static class RequestLoggingMiddlewareExtensions
+{
+ public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
+ {
+ return builder.UseMiddleware();
+ }
+}