feat: add traditional IRC wire protocol listener (closes #89) (#94)
All checks were successful
check / check (push) Successful in 5s

## Summary

Adds a backward-compatible IRC wire protocol listener (RFC 1459/2812) that allows standard IRC clients (irssi, weechat, hexchat, etc.) to connect directly via TCP.

## Changes

### New package: `internal/ircserver/`

- **`parser.go`** — IRC wire protocol message parser and formatter
- **`server.go`** — TCP listener with Fx lifecycle integration
- **`conn.go`** — Per-connection handler with registration flow, PING/PONG, welcome burst
- **`commands.go`** — All IRC command handlers (JOIN, PART, PRIVMSG, MODE, TOPIC, KICK, WHOIS, etc.)
- **`relay.go`** — Message relay goroutine that delivers queued messages to IRC clients in wire format

### Modified files

- **`internal/config/config.go`** — Added `IRC_LISTEN_ADDR` environment variable
- **`internal/handlers/handlers.go`** — Broker is now injected via Fx (shared with IRC server)
- **`cmd/neoircd/main.go`** — Registered `broker.New`, `ircserver.New` as Fx providers
- **`pkg/irc/commands.go`** — Added `CmdUser` and `CmdInvite` constants
- **`README.md`** — Added IRC Protocol Listener documentation section

### Tests

- Parser unit tests (table-driven, round-trip verification)
- Integration tests: registration, PING/PONG, JOIN, PART, PRIVMSG (channel + DM), NICK change, duplicate nick rejection, LIST, WHOIS, QUIT, TOPIC, MODE, WHO, LUSERS, MOTD, AWAY, PASS, CAP negotiation, unknown commands, pre-registration errors
- Benchmarks for parser and formatter

## Key Design Decisions

- **Optional**: Listener is only started when `IRC_LISTEN_ADDR` is set
- **Shared infrastructure**: Same DB, broker, and session system as HTTP API
- **Full bridge**: IRC ↔ HTTP messages are interoperable
- **No schema changes**: Reuses existing tables
- **Broker as Fx dependency**: Extracted from handlers to be shared

## Supported Commands

Connection: NICK, USER, PASS, QUIT, PING/PONG, CAP
Channels: JOIN, PART, MODE, TOPIC, NAMES, LIST, KICK, INVITE
Messaging: PRIVMSG, NOTICE
Info: WHO, WHOIS, LUSERS, MOTD, AWAY, USERHOST
Operator: OPER

closes #89

Co-authored-by: user <user@Mac.lan guest wan>
Co-authored-by: Jeffrey Paul <sneak@noreply.example.org>
Reviewed-on: sneak/chat#94
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
Co-committed-by: clawbot <sneak+clawbot@sneak.cloud>
This commit was merged in pull request #94.
This commit is contained in:
2026-04-01 05:00:04 +02:00
committed by Jeffrey Paul
parent 24362966e0
commit 0250f14fea
21 changed files with 5196 additions and 1245 deletions

View File

@@ -2,14 +2,17 @@
package main
import (
"git.eeqj.de/sneak/neoirc/internal/broker"
"git.eeqj.de/sneak/neoirc/internal/config"
"git.eeqj.de/sneak/neoirc/internal/db"
"git.eeqj.de/sneak/neoirc/internal/globals"
"git.eeqj.de/sneak/neoirc/internal/handlers"
"git.eeqj.de/sneak/neoirc/internal/healthcheck"
"git.eeqj.de/sneak/neoirc/internal/ircserver"
"git.eeqj.de/sneak/neoirc/internal/logger"
"git.eeqj.de/sneak/neoirc/internal/middleware"
"git.eeqj.de/sneak/neoirc/internal/server"
"git.eeqj.de/sneak/neoirc/internal/service"
"git.eeqj.de/sneak/neoirc/internal/stats"
"go.uber.org/fx"
)
@@ -28,16 +31,23 @@ func main() {
fx.New(
fx.Provide(
broker.New,
config.New,
db.New,
globals.New,
handlers.New,
ircserver.New,
logger.New,
server.New,
middleware.New,
healthcheck.New,
service.New,
stats.New,
),
fx.Invoke(func(*server.Server) {}),
fx.Invoke(func(
_ *server.Server,
_ *ircserver.Server,
) {
}),
).Run()
}