feat: add ERP agent pet bridge and startup guide
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Lskj.AgentPet.Host.Core.AstrBot;
|
||||
|
||||
public sealed record SseFrame(string Event, string Data, string? Id);
|
||||
|
||||
public static class SseParser
|
||||
{
|
||||
public const int MaxEventCharacters = 1024 * 1024;
|
||||
|
||||
public static async IAsyncEnumerable<SseFrame> ReadAsync(
|
||||
Stream source,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
using StreamReader reader = new(
|
||||
source,
|
||||
new UTF8Encoding(false, true),
|
||||
detectEncodingFromByteOrderMarks: true,
|
||||
bufferSize: 4096,
|
||||
leaveOpen: true);
|
||||
string eventName = "message";
|
||||
string? id = null;
|
||||
StringBuilder data = new();
|
||||
|
||||
while (true)
|
||||
{
|
||||
string? line = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (line is null)
|
||||
{
|
||||
if (data.Length > 0)
|
||||
yield return new SseFrame(eventName, TrimFinalNewline(data), id);
|
||||
yield break;
|
||||
}
|
||||
if (line.Length == 0)
|
||||
{
|
||||
if (data.Length > 0)
|
||||
yield return new SseFrame(eventName, TrimFinalNewline(data), id);
|
||||
eventName = "message";
|
||||
data.Clear();
|
||||
continue;
|
||||
}
|
||||
if (line[0] == ':') continue;
|
||||
|
||||
int separator = line.IndexOf(':');
|
||||
string field = separator < 0 ? line : line[..separator];
|
||||
string value = separator < 0 ? string.Empty : line[(separator + 1)..];
|
||||
if (value.StartsWith(' ')) value = value[1..];
|
||||
switch (field)
|
||||
{
|
||||
case "event":
|
||||
eventName = string.IsNullOrWhiteSpace(value) ? "message" : value;
|
||||
break;
|
||||
case "data":
|
||||
if (data.Length + value.Length + 1 > MaxEventCharacters)
|
||||
throw new HostError("astrbot_sse_event_too_large", "AstrBot SSE 单个事件超过 1 MB。 ");
|
||||
data.Append(value).Append('\n');
|
||||
break;
|
||||
case "id":
|
||||
if (!value.Contains('\0')) id = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string TrimFinalNewline(StringBuilder value)
|
||||
{
|
||||
return value.Length > 0 && value[value.Length - 1] == '\n'
|
||||
? value.ToString(0, value.Length - 1)
|
||||
: value.ToString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user