Schipper.Io.Irc connects, registers, joins one channel, relays PRIVMSG, and answers PING. Confidentiality, authentication, and envelope framing belong to the caller.
No SASL, no multi-channel, no CTCP. Lines are CRLF UTF-8. Injection characters are rejected before they hit the socket.
Joined is true only when the server confirms JOIN for this nick. A ban numeric returns so the caller can reconnect.
CR, LF, and NUL are refused. Commands over 512 UTF-8 bytes including CRLF throw and are not written. Writes are serialized.
A fixed 4096-byte read buffer survives idle timeouts. A split PING stays one PONG. A line with no LF returns instead of growing forever.
RunAsync is one attempt. The caller loops. TLS uses the default hostname check.
await using var irc = new IrcConnection( host: "irc.example.net", port: 6697, tls: true, nick: "ada", channel: "#workshop", log: line => logger.LogInformation("{Line}", line)); irc.ChannelMessage += (nick, text) => { }; await irc.RunAsync(cancellationToken);