N1MM splits the telnet stream on CR, not LF, which says some nodes send CR with no LF after it. Against those the assembler was handing the whole session back as one unfinished line. Also adds "user:" to the login prompts, which N1MM matches and we did not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
47 lines
1.4 KiB
C#
47 lines
1.4 KiB
C#
using System.Text;
|
|
|
|
namespace Nonemm.Spotting.Telnet;
|
|
|
|
/// Splits the text coming off a telnet stream into lines and keeps the tail
|
|
/// that has no line ending yet. Cluster nodes write their login prompt without
|
|
/// one, so the tail has to be readable before the line is finished.
|
|
public sealed class LineAssembler
|
|
{
|
|
private readonly StringBuilder pending = new();
|
|
private bool afterCarriageReturn;
|
|
|
|
/// What has arrived since the last line ending.
|
|
public string Pending => pending.ToString();
|
|
|
|
/// Breaks on CR, LF or CRLF. Most nodes send CRLF, but N1MM splits on CR
|
|
/// alone, which says some of them leave the LF out.
|
|
public IReadOnlyList<string> Add(string text)
|
|
{
|
|
List<string> lines = [];
|
|
foreach (char character in text)
|
|
{
|
|
bool wasAfterCarriageReturn = afterCarriageReturn;
|
|
afterCarriageReturn = character == '\r';
|
|
switch (character)
|
|
{
|
|
case '\n' when wasAfterCarriageReturn:
|
|
break;
|
|
case '\n' or '\r':
|
|
lines.Add(pending.ToString());
|
|
pending.Clear();
|
|
break;
|
|
default:
|
|
pending.Append(character);
|
|
break;
|
|
}
|
|
}
|
|
return lines;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
pending.Clear();
|
|
afterCarriageReturn = false;
|
|
}
|
|
}
|